Logging - Как пользоваться логами

CPVM has great logging system.

Параметры логирования вне фрагмента

Пример конфигурации запуска в виде json (опущено все кроме логирования):

{
    fragment: { id: "fr1", version: 240234042 }
    transactionId: "I1FKJ3389sfdku3e"
    dam: "1.2.3.255"

    ...

    logging: { 
        redirections: {      
            stdout: {
                id: "myLog"
                scope: "transaction"
                strictOrder: true
            }, 
            stderr: {
                id: "myLog"
                scope: "transaction"
                strictOrder: true
            }
        }
        allowCreateLogs: false
    }
}
  • каждый фрагмент по умлочанию имеет переопределнные sys.stderr/sys.stdout, которые будут пытаться писать в логи с идентификаторами "stderr"/"stdout"
  • для каждого запуска фрагмента можно сконфигурировать "перенаправления". Например, фрагмент пытается писать свой stderr в лог c ID "stderr", а мы перенаправляем его в лог с другим ID. В примере выше лог фрагмента "stderr" перенаправлялся в общий для всей транзакции лог "myLog" с сохранением порядка
  • если перенаправление не заданы - логи пропадают (никуда не выводятся), за исключением случая, когда allowCreateLogs=true.
  • allowCreateLogs в параметрах означает, можно ли автоматом создавать логи для фрагмента даже если для него не скнофигурировано ни одного перенаправления

Параметры логирования внутри фрагмента

import ap
import sys

sys.stdout = ap.create_log("myLogId", scope = "transaction")
sys.stderr = sys.stdout   # можно задать тот-же лог что и для stdout

Конфигурирование логов внутри фрагмента необязательно, по умолчанию для каждого фрагмента перед стартом задается следующая конфигурация:

sys.stdout = ap.create_log("stdout")
sys.stderr = ap.create_log("stderr")

3 вида логов

  • shared - записи в лог одновременно идут из разных процессов/потоков. Лог можно загружать в реальном времени. Могут быть гарантии частичного порядка, в зависимости от конфигурации лога. При перезапусках фрагментов их записи не будут удалятся из лога, поэтому для такого вида логов лучше помечать запуски фрагментов (print("my fragment started")) и включать опцию strictOrder, что теоритически позволит отбросить незавершенные части лога.
  • exclusive - только один процесс/поток может писать в данный лог. Лог можно загружать в реальном времени. Строгий порядок гарантирован при любых условиях.
  • offline shared - (НЕ ГОТОВО, в TVM io выводить может?) аналогичен shared, но смешивание записей разных процессов/потоков происходит уже после остановки транзакции, что позволяет получать целостный лог с учетом перезапусков. Данный вид лога не поддерживает скоупы user, global, а также загрузку в реальном времени.

Скоупы

Пример: scope: "transaction" - это значит, что лог с заданным ID уникален только в пределах транзакции и привязан к ее жизненному циклу

какие еще есть скоупы:

  • execution (exclusive) - лог уникален в пределах конретного запуска фрагмента и изолирован от всех других запусков.
  • fragment (shared или offline shared) - лог уникален в пределах frId (общий для всех запусков конкретного прототипа фрагмента).
  • transaction (shared или offline shared) - лог уникален в пределах транзакции (общий для всех фрагментов конкретной транзакции)
  • user (shared) - лог общий для всех транзакций юзера.

Перезапуски

При перезапуске фрагмента: exclusive-логи могут стираться (опционально), а для нового запуска создается новый лог. все что фрагмент записал в shared-лог, остается в нем навечно. Удалится записанные данные могут только в случае удаления всего лога целиком, что может произойти для логов со скоупом execution.

Как получить список всех логов

GET /vm/transactions/{trId}/logs/ - получить список логов со скоупами execution, fragment, transaction, которые привязаны к кокретной транзакции GET /vm/logs/ - получить список всех логов со скоупом user

Порядок

  • для любых параметров запуска, порядок гарнтирован в пределах одного запуска фрагмента.
  • если strictOrder в параметрах лога == true, значит в общих логах будет устанавливаться частичный порядок удовлетворяющий отношению "до-после": все записи в лог фрагмента-родителя случившиеся до запуска (call/call_async) будут всегда идти ДО записей в лог запущенного фрагмента.
  • это означает, что:
    • если все фрагменты запускаются синхронно и strictOrder = true, весь лог будет целиком строго упорядочен
    • фрагменты запускающиеся асинхронно при strictOrder = true, будут смешивать свои логи:
      • с фрагментом родителем (но только после момента запуска!)
      • с параллельно запущенными родственными фрагментами (от того же родителя - тут порядок сохраняется только для каждого фрагмента в отдельности)
  • если strictOrder = false - никаких гарантий частичного порядка между записями разных фрагментов не дается. Дебажить по таким логам тяжело, т.к. реально могут быть перемешивания во времени