Примеры обработки логов: различия между версиями
(не показаны 3 промежуточные версии этого же участника) | |||
Строка 37: | Строка 37: | ||
#* <code>UPPER</code> литерал используется для сопоставления заглавных букв. | #* <code>UPPER</code> литерал используется для сопоставления заглавных букв. | ||
#* Остальная часть контента не совпадает. | #* Остальная часть контента не совпадает. | ||
# Введите следующий фрагмент данных логов вручную в текстовое поле «'''Образец лога'''» | # Введите следующий фрагмент данных логов вручную в текстовое поле «'''Образец лога'''» <br />{ "event.type":"LOG", "content":"April 24, 2022 09:59:52 [myPool-thread-1] INFO Lorem ipsum dolor sit amet", "status":"NONE", "timestamp":"1650889391528", "log.source":"/var/log/myapp/application.log.#", "loglevel":"NONE" }<br /> | ||
# Выберите '''Проверить правило''' . Отображаются обработанные данные логов. Поля <code>timestamp</code> и <code>loglevel</code> имеют правильные значения. Дополнительный атрибут <code>thread.name</code> также правильно извлечен | # Выберите '''Проверить правило''' . Отображаются обработанные данные логов. Поля <code>timestamp</code> и <code>loglevel</code> имеют правильные значения. Дополнительный атрибут <code>thread.name</code> также правильно извлечен <br />{ "content":"April 24, 2022 09:59:52 [myPool-thread-1] INFO Lorem ipsum dolor sit amet", "timestamp":"1650794392000", "event.type":"LOG", "status":"NONE", "log.source":"/var/log/myapp/application.log.#", "loglevel":"INFO", "thread.name":"myPool-thread-1" }<br /><br />Сохраните правило обработки лога. | ||
По мере поступления новых данных логов вы сможете увидеть обработанные данные логов в средстве просмотра логов. | По мере поступления новых данных логов вы сможете увидеть обработанные данные логов в средстве просмотра логов. | ||
Строка 70: | Строка 70: | ||
# Введите '''Название правила''' и запрос лога. Для запроса лога используйте постоянную фразу из содержимого данных лога для <code>cloud.provider="aws"</code>и <code>content="Billed Duration"</code> Название правила : <code>AWS services - billed duration</code> Соответствие : <code>cloud.provider="aws" and content="Billed Duration"</code> | # Введите '''Название правила''' и запрос лога. Для запроса лога используйте постоянную фразу из содержимого данных лога для <code>cloud.provider="aws"</code>и <code>content="Billed Duration"</code> Название правила : <code>AWS services - billed duration</code> Соответствие : <code>cloud.provider="aws" and content="Billed Duration"</code> | ||
# Введите '''определение процесса''' для анализа значения тарифицированной длительности. Определение процесса : <code>PARSE(content, "LD 'Billed Duration:' SPACE? INT:aws.billed.duration")</code> | # Введите '''определение процесса''' для анализа значения тарифицированной длительности. Определение процесса : <code>PARSE(content, "LD 'Billed Duration:' SPACE? INT:aws.billed.duration")</code> | ||
# Предполагая, что вы наблюдали следующую запись лога в средстве просмотра логов, вы можете выбрать '''Скачать образец лога''' и автоматически заполнить текстовое поле '''Образец лога''' вашими данными лога. <code>REPORT RequestId: 000d000-0e00-0d0b-a00e-aec0aa0000bc Duration: 5033.50 ms Billed Duration: 5034 ms Memory Size: 1024 MB Max Memory Used: 80 MB Init Duration: 488.08 ms</code> В качестве альтернативы вы можете вручную ввести следующий фрагмент данных лога (содержащий другие дополнительные атрибуты) в текстовое поле | # Предполагая, что вы наблюдали следующую запись лога в средстве просмотра логов, вы можете выбрать '''Скачать образец лога''' и автоматически заполнить текстовое поле '''Образец лога''' вашими данными лога. <code>REPORT RequestId: 000d000-0e00-0d0b-a00e-aec0aa0000bc Duration: 5033.50 ms Billed Duration: 5034 ms Memory Size: 1024 MB Max Memory Used: 80 MB Init Duration: 488.08 ms</code> В качестве альтернативы вы можете вручную ввести следующий фрагмент данных лога (содержащий другие дополнительные атрибуты) в текстовое поле <br />Образец лога <br />{ "event.type": "LOG", "content": "REPORT RequestId: 000d000-0e00-0d0b-a00e-aec0aa0000bc\tDuration: 5033.50 ms\tBilled Duration: 5034 ms\tMemory Size: 1024 MB\tMax Memory Used: 80 MB\t\n", "status": "INFO", "timestamp": "1651062483672", "cloud.provider": "aws", "cloud.account.id": "999999999999", "cloud.region": "eu-central-1", "aws.log_group": "/aws/lambda/aws-dev", "aws.log_stream": "2022/04/27/[$LATEST]0d00000daa0c0c0a0a0e0ea0eccc000f", "aws.region": "central-1", "aws.account.id": "999999999999", "aws.service": "lambda", "aws.resource.id": "aws-dev", "aws.arn": "arn:aws:lambda:central-1:999999999999:function:aws-dev", "cloud.log_forwarder": "999999999999:central-1:dynatrace-aws-logs", "loglevel": "INFO" } | ||
# Выберите '''Проверить правило''' . Отображаются обработанные данные лога. Отображаемые обработанные данные лога обогащены новым атрибутом <code>aws.billed.duration</code>. | # Выберите '''Проверить правило''' . Отображаются обработанные данные лога. Отображаемые обработанные данные лога обогащены новым атрибутом <code>aws.billed.duration</code>. <br />{ "event.type": "LOG", "content": "REPORT RequestId: 000d000-0e00-0d0b-a00e-aec0aa0000bc\tDuration: 5033.50 ms\tBilled Duration: 5034 ms\tMemory Size: 1024 MB\tMax Memory Used: 80 MB\t\n", "status": "INFO", "timestamp": "1651062483672", "cloud.provider": "aws", "cloud.account.id": "999999999999", "cloud.region": "eu-central-1", "aws.log_group": "/aws/lambda/aws-dev", "aws.log_stream": "2022/04/27/[$LATEST]0d00000daa0c0c0a0a0e0ea0eccc000f", "aws.region": "central-1", "aws.account.id": "999999999999", "aws.service": "lambda", "aws.resource.id": "aws-dev", "aws.arn": "arn:aws:lambda:central-1:999999999999:function:aws-dev", "cloud.log_forwarder": "999999999999:central-1:dynatrace-aws-logs", "loglevel": "INFO" } | ||
# Сохраните правило обработки лога. | # Сохраните правило обработки лога. | ||
# Перейдите в '''Настройки > Мониторинг логов > Извлечение метрик''' и выберите '''Добавить метрику лога''' . | # Перейдите в '''Настройки > Мониторинг логов > Извлечение метрик''' и выберите '''Добавить метрику лога''' . | ||
Строка 94: | Строка 94: | ||
* Парсинг поля из JSON в плоском режиме. Вы можете использовать JSON-соответствие и настроить его для извлечения нужных полей в качестве атрибутов лога верхнего уровня. Соответствие в плоском режиме автоматически создает атрибуты и называет их точно так же, как и соответствующие имена полей JSON. Затем вы можете использовать команду <code>FIELDS_RENAME</code>, чтобы задать имена, которые вам подходят. Определение правила обработки <code>PARSE(content, "JSON{STRING:stringField}(flat=true)")</code> <code>| FIELDS_RENAME(better.name: stringField)</code> <br />Результат после преобразования <code>{</code> <code> "content": "{\"intField\": 13, \"stringField\": \"someValue\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }",</code> <code> "better.name": "someValue"</code> <code>}</code> | * Парсинг поля из JSON в плоском режиме. Вы можете использовать JSON-соответствие и настроить его для извлечения нужных полей в качестве атрибутов лога верхнего уровня. Соответствие в плоском режиме автоматически создает атрибуты и называет их точно так же, как и соответствующие имена полей JSON. Затем вы можете использовать команду <code>FIELDS_RENAME</code>, чтобы задать имена, которые вам подходят. Определение правила обработки <code>PARSE(content, "JSON{STRING:stringField}(flat=true)")</code> <code>| FIELDS_RENAME(better.name: stringField)</code> <br />Результат после преобразования <code>{</code> <code> "content": "{\"intField\": 13, \"stringField\": \"someValue\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }",</code> <code> "better.name": "someValue"</code> <code>}</code> | ||
* Разбор вложенного поля из JSON. Вы также можете разобрать больше полей (включая вложенные) с помощью JSON-соответствия без плоского режима. В результате вы получаете <code>VariantObject</code>, который можете обрабатывать дальше. Например, вы можете создать атрибут верхнего уровня из его внутренних полей. | * Разбор вложенного поля из JSON. Вы также можете разобрать больше полей (включая вложенные) с помощью JSON-соответствия без плоского режима. В результате вы получаете <code>VariantObject</code>, который можете обрабатывать дальше. Например, вы можете создать атрибут верхнего уровня из его внутренних полей. <br />Определение правила обработки <br />PARSE(content, " JSON{ STRING:stringField, JSON {STRING:nestedStringField1}:nested }:parsedJson") | FIELDS_ADD(top_level.attribute1: parsedJson["stringField"], top_level.attribute2: parsedJson["nested"]["nestedStringField1"]) | FIELDS_REMOVE(parsedJson)<br /> <br />Результат после преобразования <br />{ "content": "{\"intField\": 13, \"stringField\": \"someValue\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }", "top_level.attribute1": "someValue", "top_level.attribute2": "someNestedValue1" } | ||
* Анализ всех полей из JSON в режиме автообнаружения. Иногда вам интересны все поля JSON. Вам не нужно перечислять все атрибуты. Вместо этого можно использовать JSON-соответствие в режиме автообнаружения. В результате вы получаете <code>VARIANT_OBJECT</code>, который можно обрабатывать дальше. Например, вы можете создать атрибут верхнего уровня из его внутренних полей. | * Анализ всех полей из JSON в режиме автообнаружения. Иногда вам интересны все поля JSON. Вам не нужно перечислять все атрибуты. Вместо этого можно использовать JSON-соответствие в режиме автообнаружения. В результате вы получаете <code>VARIANT_OBJECT</code>, который можно обрабатывать дальше. Например, вы можете создать атрибут верхнего уровня из его внутренних полей. <br />Определение правила обработки <br />PARSE(content,"JSON:parsedJson") | FIELDS_ADD(f1: parsedJson["intField"], f2:parsedJson["stringField"], f3:parsedJson["nested"]["nestedStringField1"], f4:parsedJson["nested"]["nestedStringField2"]) | FIELDS_REMOVE(parsedJson)<br /> Результат после преобразования <br />{ "content": "{\"intField\": 13, \"stringField\": \"someValue\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }", "f1": "13", "f2": "someValue", "f3": "someNestedValue1", "f4": "someNestedValue2" } | ||
*Анализ любого поля из JSON, обработка контента как обычного текста. При таком подходе вы можете назвать атрибут как вам угодно, но правило обработки становится более сложным. | *Анализ любого поля из JSON, обработка контента как обычного текста. При таком подходе вы можете назвать атрибут как вам угодно, но правило обработки становится более сложным. <br />Определение правила обработки <br />PARSE(content, "LD '\"stringField\"' SPACE? ':' SPACE? DQS:newAttribute ")<br /> Результат после преобразования <br />{ "content": "{\"intField\": 13, \"stringField\": \"someValue\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }", "newAttribute": "someValue" } | ||
=== Пример 5: Анализ атрибутов из разных форматов === | === Пример 5: Анализ атрибутов из разных форматов === | ||
Строка 376: | Строка 376: | ||
Все событие лога может быть удалено с помощью команды <code>FILTER_OUT</code>. Событие удаляется, когда выполняется условие, переданное в качестве параметра команды. | Все событие лога может быть удалено с помощью команды <code>FILTER_OUT</code>. Событие удаляется, когда выполняется условие, переданное в качестве параметра команды. | ||
* '''Отбрасывание на основе прематчера -''' В большинстве случаев достаточно отбросить каждое событие, которое было предварительно сопоставлено. Например, если мы хотим удалить все события <code>DEBUG</code> и <code>TRACE</code>, мы можем настроить запрос сопоставления на соответствие любому из этих статусов, а затем использовать команду <code>FILTER_OUT</code> для перехвата всего. | * '''Отбрасывание на основе прематчера -''' В большинстве случаев достаточно отбросить каждое событие, которое было предварительно сопоставлено. Например, если мы хотим удалить все события <code>DEBUG</code> и <code>TRACE</code>, мы можем настроить запрос сопоставления на соответствие любому из этих статусов, а затем использовать команду <code>FILTER_OUT</code> для перехвата всего. Соответствие <br /><code>status="DEBUG" or status="TRACE"</code> <br /> Определение правила обработки <br /><code>FILTER_OUT(true)</code> <br /> Пример данных лога <br /><code>{</code> <code> "status": "DEBUG",</code> <code> "content":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac neque nisi. Nunc accumsan sollicitudin lacus."</code> <code>}</code> <br /> Таким образом, все логи со статусом <code>DEBUG</code> или <code>TRACE</code> удаляются. | ||
* Расширенное условие отбрасывания Также можно использовать дополнительную логику и не отбрасывать все предварительно сопоставленные события. В следующем примере мы отбрасываем входящие события, время выполнения которых составляет менее 100 мс. Пример данных лога <code>{</code> <code> "content":"2022-06-23 06:52:35.280 UTC INFO My monitored service call took 97ms"</code> <code>}</code> <br />Определение правила обработки <code>PARSE(content, "LD 'My monitored service call took ' INT:took 'ms'")</code> <code>| FILTER_OUT(took < 100)</code> <code>| FIELDS_REMOVE(took)</code> | * Расширенное условие отбрасывания Также можно использовать дополнительную логику и не отбрасывать все предварительно сопоставленные события. В следующем примере мы отбрасываем входящие события, время выполнения которых составляет менее 100 мс. Пример данных лога <code>{</code> <code> "content":"2022-06-23 06:52:35.280 UTC INFO My monitored service call took 97ms"</code> <code>}</code> <br />Определение правила обработки <code>PARSE(content, "LD 'My monitored service call took ' INT:took 'ms'")</code> <code>| FILTER_OUT(took < 100)</code> <code>| FIELDS_REMOVE(took)</code> | ||
Строка 382: | Строка 382: | ||
Всякий раз, когда содержимое или любой другой атрибут должен быть изменен, он должен быть объявлен как <code>INOUT</code> (записываемый) с помощью команды <code>USING</code>. <code>REPLACE_PATTERN</code> - Это очень мощная функция, которая может быть полезна, когда мы хотим замаскировать некоторую часть атрибута. | Всякий раз, когда содержимое или любой другой атрибут должен быть изменен, он должен быть объявлен как <code>INOUT</code> (записываемый) с помощью команды <code>USING</code>. <code>REPLACE_PATTERN</code> - Это очень мощная функция, которая может быть полезна, когда мы хотим замаскировать некоторую часть атрибута. | ||
* В следующем примере мы маскируем IP-адрес, устанавливая значение 0 для последнего октета. | * В следующем примере мы маскируем IP-адрес, устанавливая значение 0 для последнего октета. <br />Определение правила обработки <br /><code>USING(INOUT ip)</code> <code>| FIELDS_ADD(ip: IPADDR(ip) & 0xFFFFFF00l)</code><br /> Пример данных лога <br /><code>{</code> <code> "content":"Lorem ipsum",</code> <code> "timestamp": "1656009021053",</code> <code> "ip": "192.168.0.12"</code> <code>}</code><br /> Результат после преобразования <br /><code>{</code> <code> "content": "Lorem ipsum",</code> <code> "timestamp": "1656009021053",</code> <code> "ip": "192.168.0.0"</code> <code>}</code> | ||
* В следующем примере мы маскируем IP-адрес, устанавливая значение <code>xxx</code> последнего отчета. | * В следующем примере мы маскируем IP-адрес, устанавливая значение <code>xxx</code> последнего отчета. <br />Определение правила обработки <br /><code>USING(INOUT ip)</code> <code>| FIELDS_ADD(ip: REPLACE_PATTERN(ip, "(INT'.'INT'.'INT'.'):not_masked INT", "${not_masked}xxx"))</code><br /> Пример данных лога <br /><code>{</code> <code> "content":"Lorem ipsum",</code> <code> "timestamp": "1656009021053",</code> <code> "ip": "192.168.0.12"</code> <code>}</code><br /> Результат после преобразования <br /><code>{</code> <code> "content": "Lorem ipsum",</code> <code> "timestamp": "1656009021053",</code> <code> "ip": "192.168.0.xxx"</code> <code>}</code> | ||
* В следующем примере мы маскируем весь адрес электронной почты, используя <code>sha1</code> (алгоритм защищенного хэширования) | * В следующем примере мы маскируем весь адрес электронной почты, используя <code>sha1</code> (алгоритм защищенного хэширования) Определение правила обработки <br /><code>USING(INOUT email)</code> <code>| FIELDS_ADD(email: REPLACE_PATTERN(email, "LD:email_to_be_masked", "${email_to_be_masked|sha1}"))</code><br /> Пример данных лога <br /><code>{</code> <code> "content":"Lorem ipsum",</code> <code> "timestamp": "1656009924312",</code> <code> "email": "john.doe@astromkey.com"</code> <code>}</code><br /> Результат после преобразования <br /><code>{</code> <code> "content": "Lorem ipsum",</code> <code> "timestamp": "1656009924312",</code> <code> "email": "9940e79e41cbf7cc452b137d49fab61e386c602d"</code> <code>}</code> | ||
* В следующем примере мы скрываем IP-адрес, адрес электронной почты и номер кредитной карты из поля содержимого. | * В следующем примере мы скрываем IP-адрес, адрес электронной почты и номер кредитной карты из поля содержимого. <br />Определение правила обработки <br /><code>USING(INOUT content)</code> <br /><code>| FIELDS_ADD(content: REPLACE_PATTERN(content, "</code> <br /><code>(LD 'ip: '):p1 // Lorem ipsum ip:</code> <br /><code>(INT'.'INT'.'INT'.'):ip_not_masked // 192.168.0.</code> <br /><code>INT // 12</code> <br /><code>' email: ':p2 // email:</code> <br /><code>LD:email_name '@' LD:email_domain // john.doe@astromkey.com</code> <br /><code>' card number: ': p3 // card number:</code> <br /><code>CREDITCARD:card // 4012888888881881</code> <br /><code>", "${p1}${ip_not_masked}xxx${p2}${email_name|md5}@${email_domain}${p3}${card|sha1}"))</code><br /> Пример данных лога <br /><code>{</code> <code> "timestamp": "1656010291511",</code> <br /><code> "content": "Lorem ipsum ip: 192.168.0.12 email: john.doe@astromkey.com card number: 4012888888881881 dolor sit amet"</code> <code>}</code><br /> Результат после преобразования <br /><code>{</code> <code> "content": "Lorem ipsum ip: 192.168.0.xxx email: abba0b6ff456806bab66baed93e6d9c4@astromkey.com card number: 62163a017b168ad4a229c64ae1bed6ffd5e8fb2d dolor sit amet",</code> <br /><code> "timestamp": "1656010291511"</code> <code>}</code> | ||
=== Пример 14: Переименование атрибутов === | === Пример 14: Переименование атрибутов === |
Текущая версия на 18:13, 1 декабря 2024
В зависимости от созданных вами правил вы можете настроить входящие данные логов в соответствии с вашими потребностями. Ниже приведены примеры сценариев обработки данных.
- Пример 1 — Исправление нераспознанных таймфреймов и уровня логов, отображаемых в средстве просмотра логов, на основе сопоставленного источника логов.
- Пример 2 — Определение доступного для поиска настраиваемого атрибута с использованием извлеченного идентификатора из совпавшей фразы в содержимом логов.
- Пример 3 — Создание метрики продолжительной оплаты для служб AWS, используя данные логов.
- Пример 4 — Извлечение определенных полей из содержимого JSON.
- Пример 5 — Анализ атрибутов из разных форматов в одном выражении шаблона.
- Пример 6 — Несколько команд PARSE в одном правиле обработки.
- Пример 7 — Использование специализированных соответствий.
- Пример 8 — Манипулирование любым атрибутом лога (не только содержимым).
- Пример 9 — Добавление нового атрибута в текущую структуру событий логов.
- Пример 10 — Базовые математические вычисления по атрибутам.
- Пример 11 — Удаление определенного атрибута из сообщения лога.
- Пример 12 — Удаление всего события лога.
- Пример 13 — Маскировка любого атрибута.
- Пример 14 — Переименование атрибутов.
- Пример 15 — Типы данных поля ввода.
Пример 1: Исправление нераспознанных таймфреймов и уровня логов
Вы можете исправить нераспознанный таймфрейм и уровень лога, видимые в средстве просмотра логов, на основе сопоставленного источника логов. Для этого примера предположим, что вы видите сохраненное событие в средстве просмотра логов из приложения log.source
, которое установлено на /var/log/myapp/application.log.#
Вы замечаете несколько вещей, которые хотите исправить:
- лог содержит нераспознанный формат таймфрейма, который вы хотите рассматривать как таймфрейм события логов.
- Не обнаружено надлежащего уровня лога.
Итак, вы хотите преобразовать данные логов, чтобы они содержали правильные значения в полях timestamp и logLevel, и хотите добавить новый атрибут thread.name
, содержащий правильно извлеченное значение.
Чтобы создать правило обработки
- Скопируйте запрос просмотра лога в буфер обмена (
log.source="/var/log/myapp/application.log.#"
). - Перейдите в Настройки > Мониторинг логов> Обработка и выберите Добавить правило.
- Введите Название правила и скопированный запрос лога из буфера обмена. Название правила :
MyApp log processor
Соответствие :log.source="/var/log/myapp/application.log.#"
- Введите определение процесса для анализа временной метки, имени потока и уровня лога. Определение процесса :
PARSE(content, "TIMESTAMP('MMMMM d, yyyy HH:mm:ss'):timestamp ' [' LD:thread.name '] ' UPPER:loglevel")
где:TIMESTAMP
соответствие используется для поиска определенного формата даты и времени, а совпавшее значение устанавливается как существующий атрибут лога меток времени.LD
(Строковые данные) соответствие используется для сопоставления любых символов между литералами' ['
и'] '
.UPPER
литерал используется для сопоставления заглавных букв.- Остальная часть контента не совпадает.
- Введите следующий фрагмент данных логов вручную в текстовое поле «Образец лога»
{ "event.type":"LOG", "content":"April 24, 2022 09:59:52 [myPool-thread-1] INFO Lorem ipsum dolor sit amet", "status":"NONE", "timestamp":"1650889391528", "log.source":"/var/log/myapp/application.log.#", "loglevel":"NONE" } - Выберите Проверить правило . Отображаются обработанные данные логов. Поля
timestamp
иloglevel
имеют правильные значения. Дополнительный атрибутthread.name
также правильно извлечен
{ "content":"April 24, 2022 09:59:52 [myPool-thread-1] INFO Lorem ipsum dolor sit amet", "timestamp":"1650794392000", "event.type":"LOG", "status":"NONE", "log.source":"/var/log/myapp/application.log.#", "loglevel":"INFO", "thread.name":"myPool-thread-1" }
Сохраните правило обработки лога.
По мере поступления новых данных логов вы сможете увидеть обработанные данные логов в средстве просмотра логов.
Пример 2: Определение настраиваемого атрибута для поиска
Вы можете определить доступный для поиска пользовательский атрибут, используя извлеченный идентификатор из совпавшей фразы в содержимом лога.
В этом примере вы видите следующую строку лога в файле лога (еще не сохраненную в Ключ-АСТРОМ), и вы хотите извлечь идентификатор из этой строки лога, чтобы сделать ее доступной для поиска в средстве просмотра логов.
2022-04-26 10:53:01 UTC ERROR Critical error occurred for product ID: 12345678 Lorem ipsum dolor sit amet
- Перейдите в Настройки > Мониторинг логов> Обработка и выберите Добавить правило..
- Введите Название правила и запрос лога. Для запроса лога используйте постоянную фразу из содержимого данных лога (
content="Critical error occurred for product ID"
) Название правила :MyApp product ID with error
Соответствие :content="Critical error occurred for product ID"
- Введите определение процесса для анализа идентификатора. Определение процесса :
PARSE(content, "LD 'product ID:' SPACE? INT:my.product.id")
- Предполагая, что вы наблюдали следующую запись лога в средстве просмотра логов, вы можете выбрать Скачать образец лога и автоматически заполнить текстовое поле Образец лога вашими данными лога.
2022-04-26 10:53:01 UTC ERROR Critical error occurred for product ID: 12345678 Lorem ipsum dolor sit amet
В качестве альтернативы вы можете вручную вставить наблюдаемую запись лога как содержимое записи лога в текстовое поле Образец лога{
"content": "2022-04-26 10:53:01 UTC ERROR Critical error occurred for product ID: 12345678 Lorem ipsum dolor sit amet"
}
- Выберите Проверить правило . Отображаются обработанные данные лога. Отображаемые обработанные данные лога обогащаются разобранным идентификатором продукта
{
"content": "2022-04-26 10:53:01 UTC ERROR Critical error occurred for product ID: 12345678 Lorem ipsum dolor sit amet",
"timestamp": "1650961124832",
"my.product.id": "12345678"
}
- Сохраните правило обработки лога.
- Перейдите в Настройки > Мониторинг логов > Пользовательские атрибуты и выберите Добавить пользовательский атрибут .
- Создайте пользовательский атрибут на основе проанализированного идентификатора продукта (
my.product.id
). Ключ :my.product.id
- Сохраните свой пользовательский атрибут.
- Теперь вы можете искать и фильтровать данные лога по атрибуту
my.product.id
в средстве просмотра логов.
Пример 3. Создание метрики продолжительной оплаты для служб AWS, используя данные логов
В этом примере вы хотите отслеживать фактическую тарифицированную длительность из ваших сервисов AWS. Вы хотите использовать атрибут cloud.provider
со значением в ваших данных лога aws
. В средстве просмотра логов вы видите запись лога, содержащую следующую строку:
REPORT RequestId: 000d000-0e00-0d0b-a00e-aec0aa0000bc Duration: 5033.50 ms Billed Duration: 5034 ms Memory Size: 1024 MB Max Memory Used: 80 MB Init Duration: 488.08 ms
Кроме того, эта запись лога содержит cloud.provider
атрибут со значением aws
.
- Перейдите в Настройки > Мониторинг логов > Обработка и выберите Добавить правило .
- Введите Название правила и запрос лога. Для запроса лога используйте постоянную фразу из содержимого данных лога для
cloud.provider="aws"
иcontent="Billed Duration"
Название правила :AWS services - billed duration
Соответствие :cloud.provider="aws" and content="Billed Duration"
- Введите определение процесса для анализа значения тарифицированной длительности. Определение процесса :
PARSE(content, "LD 'Billed Duration:' SPACE? INT:aws.billed.duration")
- Предполагая, что вы наблюдали следующую запись лога в средстве просмотра логов, вы можете выбрать Скачать образец лога и автоматически заполнить текстовое поле Образец лога вашими данными лога.
REPORT RequestId: 000d000-0e00-0d0b-a00e-aec0aa0000bc Duration: 5033.50 ms Billed Duration: 5034 ms Memory Size: 1024 MB Max Memory Used: 80 MB Init Duration: 488.08 ms
В качестве альтернативы вы можете вручную ввести следующий фрагмент данных лога (содержащий другие дополнительные атрибуты) в текстовое поле
Образец лога
{ "event.type": "LOG", "content": "REPORT RequestId: 000d000-0e00-0d0b-a00e-aec0aa0000bc\tDuration: 5033.50 ms\tBilled Duration: 5034 ms\tMemory Size: 1024 MB\tMax Memory Used: 80 MB\t\n", "status": "INFO", "timestamp": "1651062483672", "cloud.provider": "aws", "cloud.account.id": "999999999999", "cloud.region": "eu-central-1", "aws.log_group": "/aws/lambda/aws-dev", "aws.log_stream": "2022/04/27/[$LATEST]0d00000daa0c0c0a0a0e0ea0eccc000f", "aws.region": "central-1", "aws.account.id": "999999999999", "aws.service": "lambda", "aws.resource.id": "aws-dev", "aws.arn": "arn:aws:lambda:central-1:999999999999:function:aws-dev", "cloud.log_forwarder": "999999999999:central-1:dynatrace-aws-logs", "loglevel": "INFO" } - Выберите Проверить правило . Отображаются обработанные данные лога. Отображаемые обработанные данные лога обогащены новым атрибутом
aws.billed.duration
.
{ "event.type": "LOG", "content": "REPORT RequestId: 000d000-0e00-0d0b-a00e-aec0aa0000bc\tDuration: 5033.50 ms\tBilled Duration: 5034 ms\tMemory Size: 1024 MB\tMax Memory Used: 80 MB\t\n", "status": "INFO", "timestamp": "1651062483672", "cloud.provider": "aws", "cloud.account.id": "999999999999", "cloud.region": "eu-central-1", "aws.log_group": "/aws/lambda/aws-dev", "aws.log_stream": "2022/04/27/[$LATEST]0d00000daa0c0c0a0a0e0ea0eccc000f", "aws.region": "central-1", "aws.account.id": "999999999999", "aws.service": "lambda", "aws.resource.id": "aws-dev", "aws.arn": "arn:aws:lambda:central-1:999999999999:function:aws-dev", "cloud.log_forwarder": "999999999999:central-1:dynatrace-aws-logs", "loglevel": "INFO" } - Сохраните правило обработки лога.
- Перейдите в Настройки > Мониторинг логов > Извлечение метрик и выберите Добавить метрику лога .
- Создайте метрику лога на основе проанализированного идентификатора продукта (
aws.billed.duration
). Ключ :log.aws.billed.duration
Запрос :cloud.provider="aws" and content="Billed Duration"
Мера :Attribute value
Атрибут :aws.billed.duration
- Сохраните метрику лога.
- Метрика
log.aws.billed.duration
видна в Визуализации метрик, и вы можете использовать ее в Ключ-АСТРОМ, как и любую другую метрику. Вы можете добавить ее на свой дашборд, включить в анализ и даже использовать ее для создания оповещений.
- Доступность метрики логов в Ключ-АСТРОМ Созданная метрика логов доступна только тогда, когда новые данные лога принимаются и соответствуют запросу лога, определенному во время создания метрики лога. Убедитесь, что новые данные лога приняты, прежде чем использовать метрику лога в других областях Ключ-АСТРОМ.
Пример 4: Извлечение определенных полей из содержимого JSON
В этом примере вы видите строку лога, имеющую следующую структуру JSON:
{"intField": 13, "stringField": "someValue", "nested": {"nestedStringField1": "someNestedValue1", "nestedStringField2": "someNestedValue2"} }
Пример лога будет выглядеть следующим образом
{
"content": "{\"intField\": 13, \"stringField\": \"someValue\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }" } |
- Парсинг поля из JSON в плоском режиме. Вы можете использовать JSON-соответствие и настроить его для извлечения нужных полей в качестве атрибутов лога верхнего уровня. Соответствие в плоском режиме автоматически создает атрибуты и называет их точно так же, как и соответствующие имена полей JSON. Затем вы можете использовать команду
FIELDS_RENAME
, чтобы задать имена, которые вам подходят. Определение правила обработкиPARSE(content, "JSON{STRING:stringField}(flat=true)")
| FIELDS_RENAME(better.name: stringField)
Результат после преобразования{
"content": "{\"intField\": 13, \"stringField\": \"someValue\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }",
"better.name": "someValue"
}
- Разбор вложенного поля из JSON. Вы также можете разобрать больше полей (включая вложенные) с помощью JSON-соответствия без плоского режима. В результате вы получаете
VariantObject
, который можете обрабатывать дальше. Например, вы можете создать атрибут верхнего уровня из его внутренних полей.
Определение правила обработки
PARSE(content, " JSON{ STRING:stringField, JSON {STRING:nestedStringField1}:nested }:parsedJson") | FIELDS_ADD(top_level.attribute1: parsedJson["stringField"], top_level.attribute2: parsedJson["nested"]["nestedStringField1"]) | FIELDS_REMOVE(parsedJson)
Результат после преобразования
{ "content": "{\"intField\": 13, \"stringField\": \"someValue\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }", "top_level.attribute1": "someValue", "top_level.attribute2": "someNestedValue1" } - Анализ всех полей из JSON в режиме автообнаружения. Иногда вам интересны все поля JSON. Вам не нужно перечислять все атрибуты. Вместо этого можно использовать JSON-соответствие в режиме автообнаружения. В результате вы получаете
VARIANT_OBJECT
, который можно обрабатывать дальше. Например, вы можете создать атрибут верхнего уровня из его внутренних полей.
Определение правила обработки
PARSE(content,"JSON:parsedJson") | FIELDS_ADD(f1: parsedJson["intField"], f2:parsedJson["stringField"], f3:parsedJson["nested"]["nestedStringField1"], f4:parsedJson["nested"]["nestedStringField2"]) | FIELDS_REMOVE(parsedJson)
Результат после преобразования
{ "content": "{\"intField\": 13, \"stringField\": \"someValue\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }", "f1": "13", "f2": "someValue", "f3": "someNestedValue1", "f4": "someNestedValue2" } - Анализ любого поля из JSON, обработка контента как обычного текста. При таком подходе вы можете назвать атрибут как вам угодно, но правило обработки становится более сложным.
Определение правила обработки
PARSE(content, "LD '\"stringField\"' SPACE? ':' SPACE? DQS:newAttribute ")
Результат после преобразования
{ "content": "{\"intField\": 13, \"stringField\": \"someValue\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }", "newAttribute": "someValue" }
Пример 5: Анализ атрибутов из разных форматов
Вы можете анализировать атрибуты из разных форматов в рамках одного выражения шаблона.
В этом примере одно или несколько приложений регистрируют идентификатор пользователя, который вы хотите извлечь как отдельный атрибут лога. Формат лога не является однообразным, поскольку он включает в себя различные схемы для регистрации идентификатора пользователя:
user ID=
userId=
userId:
user ID =
С помощью необязательного модификатора (вопрос ?
) и Alternative Groups
вы можете охватить все такие случаи одним шаблонным выражением
PARSE(content, "
LD //matches any text within a single line ('user'| 'User') //user or User literal SPACE? //optional space ('id'|'Id'|'ID') //matches any of these SPACE? //optional space PUNCT? //optional punctuation SPACE? //optional space INT:my.user.id ") |
Используя такое правило, вы можете извлечь идентификатор пользователя из множества различных нотаций. Например:
03/22 08:52:51 INFO user ID=1234567 Call = 0319 Result = 0
03/22 08:52:51 INFO UserId = 1234567 Call = 0319 Result = 0
03/22 08:52:51 INFO user id=1234567 Call = 0319 Result = 0
03/22 08:52:51 INFO user ID:1234567 Call = 0319 Result = 0
03/22 08:52:51 INFO User ID: 1234567 Call = 0319 Result = 0
03/22 08:52:51 INFO userid: 1234567 Call = 0319 Result = 0
Пример 6: Несколько команд PARSE в одном правиле обработки
Вы можете обрабатывать различные форматы или выполнять дополнительный анализ уже проанализированных атрибутов с помощью нескольких команд PARSE
, соединенных с помощью каналов (|
).
Например, с помощью следующего лога
{
"content": "{\"intField\": 13, \"message\": \"Error occurred for user 12345: Missing permissions\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }" } |
Во-первых, вы можете проанализировать поле сообщения, идентификатор пользователя и сообщение об ошибке
PARSE(content, "JSON{STRING:message}(flat=true)") | PARSE(message, "LD 'user ' INT:user.id ': ' LD:error.message") |
Результат
{
"content": "{\"intField\": 13, \"message\": \"Error occurred for user 12345: Missing permissions\", \"nested\": {\"nestedStringField1\": \"someNestedValue1\", \"nestedStringField2\": \"someNestedValue2\"} }", "message": "Error occurred for user 12345: Missing permissions", "user.id": "12345", "error.message": "Missing permissions" } |
Пример 7: использование специализированных соответствий
Мы предоставляем полный список соответствий, которые облегчают построение шаблонов.
Например, вы можете проанализировать следующий пример события лога
{
"content":"2022-05-11T13:23:45Z INFO 192.168.33.1 \"GET /api/v2/logs/ingest HTTP/1.0\" 200" } |
с использованием специализированных соответствий
PARSE(content, "ISO8601:timestamp SPACE UPPER:loglevel SPACE IPADDR:ip SPACE DQS:request SPACE INTEGER:code") |
и результат
{
"content": "2022-05-11T13:23:45Z INFO 192.168.33.1 \"GET /api/v2/logs/ingest HTTP/1.0\" 200", "timestamp": "1652275425000", "loglevel": "INFO", "ip": "192.168.33.1", "request": "GET /api/v2/logs/ingest HTTP/1.0", "code": "200" } |
Пример 8: Манипулирование любым атрибутом из лога (не только содержимым)
Если не указано иное, правило обработки работает только с полем содержимого только для чтения. Чтобы оно работало с различными атрибутами событий лога, необходимо использовать команду USING
.
Например, следующее правило объявляет два входных атрибута: статус записи и содержимое только для чтения. Затем оно проверяет, является ли статус WARN
и содержит ли содержимое текст error
. Если оба условия истинны, правило перезаписывает status
значением ERROR
.
Определение правила обработки
USING(INOUT status:STRING, content)
| FIELDS_ADD(status:IF_THEN(status == 'WARN' AND content CONTAINS('error'), "ERROR")) |
Пример данных лога
{
"log.source": "using", "timestamp": "1656011002196", "status": "WARN", "content":"Some error message" } |
Результат после преобразования
{
"log.source": "using", "timestamp": "1656011002196", "status": "ERROR", "content":"Some error message" } |
Пример 9: Добавить новый атрибут в текущую структуру событий лога
Команда FIELDS_ADD может использоваться для введения дополнительных атрибутов лога верхнего уровня. Следующий скрипт добавляет два атрибута: первый сохраняет длину, а второй — количество слов в поле содержимого.
Определение правила обработки
FIELDS_ADD(content.length: STRLEN(content), content.words: ARRAY_COUNT(SPLIT(content,"' '"))) |
Пример данных лога
{
"log.source": "new_attributes", "timestamp": "1656010654603", "content":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis." } |
Результат после преобразования
{
"content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis.", "timestamp": "1656010654603", "log.source": "new_attribute", "content.length": "62", "content.words": "9" } |
Пример 10: Базовые математические вычисления по атрибутам
Благодаря всем доступным функциям и операторам выполнять вычисления легко.
В следующем примере мы анализируем значения total
и failed
, вычисляем процент неудач и объединяем значение со знаком процента. Затем мы сохраняем его в новом атрибуте с именем failed.percentage
и удаляем временные поля.
Определение правила обработки
PARSE(content,"LD 'total: ' INT:total '; failed: ' INT:failed")
| FIELDS_ADD(failed.percentage: 100.0 * failed / total + '%') | FIELDS_REMOVE(total, failed) |
Пример данных лога
{
"timestamp": "1656011338522", "content":"Lorem ipsum total: 1000; failed: 250" } |
Результат после преобразования
{
"content": "Lorem ipsum total: 1000; failed: 250", "timestamp": "1656011338522", "failed.percentage": "25.0%" } |
Пример 11: Удаление определенного атрибута из сообщения лога
Чтобы удалить атрибут события, являющийся частью исходной записи, нам сначала нужно объявить его как INOUT
поле ввода с возможностью записи (опция) с помощью команды USING
, а затем явно удалить его с помощью команды FIELDS_REMOVE
, чтобы он не присутствовал в выходных данных преобразования.
В следующем примере мы объявляем тип redundant.attribute
обязательным записываемым атрибутом STRING
, а затем удаляем его.
Определение правила обработки
USING(INOUT redundant.attribute:STRING)
| FIELDS_REMOVE(redundant.attribute) |
Пример данных лога
{
"redundant.attribute": "value", "timestamp": "1656011525708", "content":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac neque nisi. Nunc accumsan sollicitudin lacus." } |
Результат после преобразования
{
"content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac neque nisi. Nunc accumsan sollicitudin lacus.", "timestamp": "1656011525708" } |
Мы могли бы использовать этот ?
символ, чтобы пометить атрибут как необязательный, чтобы преобразование все равно выполнялось и было успешным, даже если атрибут отсутствует в исходном событии.
В этом случае определение будет выглядеть так
USING(INOUT redundant.attribute:STRING?)
| FIELDS_REMOVE(redundant.attribute) |
Пример 12: Удалить все событие лога
Все событие лога может быть удалено с помощью команды FILTER_OUT
. Событие удаляется, когда выполняется условие, переданное в качестве параметра команды.
- Отбрасывание на основе прематчера - В большинстве случаев достаточно отбросить каждое событие, которое было предварительно сопоставлено. Например, если мы хотим удалить все события
DEBUG
иTRACE
, мы можем настроить запрос сопоставления на соответствие любому из этих статусов, а затем использовать командуFILTER_OUT
для перехвата всего. Соответствиеstatus="DEBUG" or status="TRACE"
Определение правила обработкиFILTER_OUT(true)
Пример данных лога{
"status": "DEBUG",
"content":"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac neque nisi. Nunc accumsan sollicitudin lacus."
}
Таким образом, все логи со статусомDEBUG
илиTRACE
удаляются. - Расширенное условие отбрасывания Также можно использовать дополнительную логику и не отбрасывать все предварительно сопоставленные события. В следующем примере мы отбрасываем входящие события, время выполнения которых составляет менее 100 мс. Пример данных лога
{
"content":"2022-06-23 06:52:35.280 UTC INFO My monitored service call took 97ms"
}
Определение правила обработкиPARSE(content, "LD 'My monitored service call took ' INT:took 'ms'")
| FILTER_OUT(took < 100)
| FIELDS_REMOVE(took)
Пример 13: Маскировка любого атрибута
Всякий раз, когда содержимое или любой другой атрибут должен быть изменен, он должен быть объявлен как INOUT
(записываемый) с помощью команды USING
. REPLACE_PATTERN
- Это очень мощная функция, которая может быть полезна, когда мы хотим замаскировать некоторую часть атрибута.
- В следующем примере мы маскируем IP-адрес, устанавливая значение 0 для последнего октета.
Определение правила обработкиUSING(INOUT ip)
| FIELDS_ADD(ip: IPADDR(ip) & 0xFFFFFF00l)
Пример данных лога{
"content":"Lorem ipsum",
"timestamp": "1656009021053",
"ip": "192.168.0.12"
}
Результат после преобразования{
"content": "Lorem ipsum",
"timestamp": "1656009021053",
"ip": "192.168.0.0"
}
- В следующем примере мы маскируем IP-адрес, устанавливая значение
xxx
последнего отчета.
Определение правила обработкиUSING(INOUT ip)
| FIELDS_ADD(ip: REPLACE_PATTERN(ip, "(INT'.'INT'.'INT'.'):not_masked INT", "${not_masked}xxx"))
Пример данных лога{
"content":"Lorem ipsum",
"timestamp": "1656009021053",
"ip": "192.168.0.12"
}
Результат после преобразования{
"content": "Lorem ipsum",
"timestamp": "1656009021053",
"ip": "192.168.0.xxx"
}
- В следующем примере мы маскируем весь адрес электронной почты, используя
sha1
(алгоритм защищенного хэширования) Определение правила обработкиUSING(INOUT email)
| FIELDS_ADD(email: REPLACE_PATTERN(email, "LD:email_to_be_masked", "${email_to_be_masked|sha1}"))
Пример данных лога{
"content":"Lorem ipsum",
"timestamp": "1656009924312",
"email": "john.doe@astromkey.com"
}
Результат после преобразования{
"content": "Lorem ipsum",
"timestamp": "1656009924312",
"email": "9940e79e41cbf7cc452b137d49fab61e386c602d"
}
- В следующем примере мы скрываем IP-адрес, адрес электронной почты и номер кредитной карты из поля содержимого.
Определение правила обработкиUSING(INOUT content)
| FIELDS_ADD(content: REPLACE_PATTERN(content, "
(LD 'ip: '):p1 // Lorem ipsum ip:
(INT'.'INT'.'INT'.'):ip_not_masked // 192.168.0.
INT // 12
' email: ':p2 // email:
LD:email_name '@' LD:email_domain // john.doe@astromkey.com
' card number: ': p3 // card number:
CREDITCARD:card // 4012888888881881
", "${p1}${ip_not_masked}xxx${p2}${email_name|md5}@${email_domain}${p3}${card|sha1}"))
Пример данных лога{
"timestamp": "1656010291511",
"content": "Lorem ipsum ip: 192.168.0.12 email: john.doe@astromkey.com card number: 4012888888881881 dolor sit amet"
}
Результат после преобразования{
"content": "Lorem ipsum ip: 192.168.0.xxx email: abba0b6ff456806bab66baed93e6d9c4@astromkey.com card number: 62163a017b168ad4a229c64ae1bed6ffd5e8fb2d dolor sit amet",
"timestamp": "1656010291511"
}
Пример 14: Переименование атрибутов
С помощью команды FIELDS_RENAME
мы можем переименовывать атрибуты, которые были частью исходного события лога, и атрибуты, созданные в процессоре. Всякий раз, когда мы хотим изменить любой атрибут исходного события, нам нужно объявить его как INOUT
(записываемый).
В следующем примере мы переименовываем существующий атрибут. Кроме того, мы извлекаем поле из JSON в плоском режиме и переименовываем новый атрибут, который был создан автоматически с именем поля JSON.
Определение правила обработки
USING(INOUT to_be_renamed, content)
| FIELDS_RENAME(better_name: to_be_renamed) | PARSE(content,"JSON{STRING:json_field_to_be_renamed}(flat=true)") | FIELDS_RENAME(another_better_name: json_field_to_be_renamed) |
Пример данных лога
{
"timestamp": "1656061626073", "content":"{\"json_field_to_be_renamed\": \"dolor sit amet\", \"field2\": \"consectetur adipiscing elit\"}", "to_be_renamed": "Lorem ipsum" } |
Результат после преобразования
{
"content": "{\"json_field_to_be_renamed\": \"dolor sit amet\", \"field2\": \"consectetur adipiscing elit\"}", "timestamp": "1656061626073", "better_name": "Lorem ipsum", "another_better_name": "dolor sit amet" } |
Пример 15: Типы данных поля ввода
Скрипт в определении процессора работает со строго типизированными данными: функции и операторы принимают только объявленные типы данных. Тип назначается всем входным полям, определенным в команде USING
, а также переменным, созданным при разборе или использовании функций приведения.
Определение правила обработки
USING(number:INTEGER, avg:DOUBLE, addr:IPADDR, arr:INTEGER[],bool:BOOLEAN, ts:TIMESTAMP)
| FIELDS_ADD(multi:number*10) | FIELDS_ADD(avgPlus1:avg+1) | FIELDS_ADD(isIP: IS_IPV6(addr)) | FIELDS_ADD(arrAvg: ARRAY_AVG(arr)) | FIELDS_ADD(negation: NOT(bool)) | FIELDS_ADD(tsAddYear: TIME_ADD_YEAR(ts,1)) |
Пример данных лога
{
"content":"Lorem ipsum", "number":"5", "avg":"123.5", "addr":"2a00:1450:4010:c05::69", "arr": ["1","2"], "bool":"false", "ts":"1984-11-30 22:19:59.789 +0000" } |
Результат после преобразования
{
"content": "Lorem ipsum", "number": "5", "avg": "123.5", "addr": "2a00:1450:4010:c05::69", "arr": [ "1", "2" ], "bool": "false", "ts": "1984-11-30 22:19:59.789 +0000", "tsAddYear": "1985-11-30T22:19:59.789000000 +0000", "negation": "true", "arrAvg": "1.5", "isIP": "true", "avgPlus1": "124.5", "multi": "50" } |