← Dynamic Workers / dynamic-workers / usage
Observability
Dynamic Workers поддерживают логи с помощью console.log() вызовы, исключения и метаданные запроса, зафиксированные во время выполнения. Чтобы получить доступ к этим логам, подключите Tail Worker, колбэк, который выполняется после завершения работы Dynamic Worker и передаёт все собранные логи, исключения и метаданные.
В этом руководстве показано, как выполнить следующее:
- Сохраняйте логи Dynamic Worker, чтобы искать, фильтровать и запрашивать их
- Собирайте логи во время выполнения и получайте их в реальном времени для разработки и отладки
Сбор логов с помощью Tail Worker
Чтобы сохранить логи, которые создаёт Dynamic Worker, их нужно перехватить и записать туда, где они смогут храниться. Для этого нужно выполнить три шага:
- Включение Workers Logs у Worker-загрузчика, чтобы вывод логов сохранялся.
- Определение Tail Worker, который получает логи от Dynamic Worker и записывает их в Workers Logs.
- Подключение Tail Worker к Dynamic Worker при его создании.
Включите Workers Logs для Worker-загрузчика
Включить Workers Logs добавив observability настройку в конфигурацию Wrangler у Worker-загрузчика. Однако Workers Logs фиксирует вывод логов только от самого Worker-загрузчика. Dynamic Worker работают отдельно, поэтому их console.log() вызовы не включаются автоматически. Чтобы логи Dynamic Worker попадали в Workers Logs, нужно определить Tail Worker, который получает логи от Dynamic Worker и записывает их в Workers Logs Worker-загрузчика.
{
"$schema": "./node_modules/wrangler/config-schema.json",
"observability": {
"enabled": true,
"head_sampling_rate": 1
}
}[observability]
enabled = true
head_sampling_rate = 1Определение Tail Worker
Когда Dynamic Worker выполняется, среда выполнения собирает все его console.log() вызовы, исключения и метаданные запроса. По умолчанию эти логи удаляются после завершения работы Dynamic Worker.
Чтобы сохранить их, определите Tail Worker для loader Worker. Tail Worker представляет собой класс с tail() метод. Здесь вы пишете код, который определяет, что происходит с логами. Runtime вызывает этот метод после завершения работы Dynamic Worker, передавая всё, что было собрано во время выполнения.
Внутри tail(), вы записываете каждую запись лога в Workers Logs, вызывая console.log() с объектом JSON. Добавьте workerId поле в каждой записи, чтобы можно было определить, какой Dynamic Worker создал каждый лог, и впоследствии фильтровать и искать логи по Dynamic Worker.
import { WorkerEntrypoint } from "cloudflare:workers";
export class DynamicWorkerTail extends WorkerEntrypoint {
async tail(events) {
for (const event of events) {
for (const log of event.logs) {
console.log({
source: "dynamic-worker-tail",
workerId: this.ctx.props.workerId,
level: log.level,
message: log.message,
});
}
}
}
}Tail Worker считывает workerId от this.ctx.props.workerId. Вы задаёте это значение при подключении Tail Worker к Dynamic Worker на следующем шаге.
Поскольку Tail Worker определяется внутри loader Worker, его console.log() вывод сохраняется в Workers Logs вместе с собственными логами Worker-загрузчика.
Подключение Tail Worker к Dynamic Worker
Когда вы создаёте Dynamic Worker, передайте Tail Worker в tails массив. Это указывает среде выполнения: после завершения этого Dynamic Worker нужно отправить собранные логи в Tail Worker, который вы определили.
Чтобы сослаться на DynamicWorkerTail класс, который вы определили на предыдущем шаге, используйте ctx.exports. ctx является третьим параметром у Worker-загрузчика в fetch(request, env, ctx) обработчик. ctx.exports дает доступ к классам, экспортированным из Worker-загрузчика. Поскольку Dynamic Worker выполняется в отдельном контексте и не может обращаться к классу напрямую, используется ctx.exports.DynamicWorkerTail() для создания ссылки, которую runtime может связать с Dynamic Worker.
Также нужно сообщить Tail Worker, для какого именно Dynamic Worker он ведёт логирование. Поскольку Tail Worker выполняется отдельно от loader Worker, fetch() обработчике, у него нет доступа к вашим локальным переменным. Чтобы передать ему информацию, используйте props опцию при создании экземпляра. props это обычный объект пар ключ-значение, который вы задаете при подключении Tail Worker и который Tail Worker может прочитать в this.ctx.props при выполнении. В этом случае вы передаёте workerId чтобы Tail Worker знал, какой Dynamic Worker создал эти логи.
const worker = env.LOADER.get(workerId, () => ({
mainModule: WORKER_MAIN,
modules: {
[WORKER_MAIN]: WORKER_SOURCE,
},
tails: [
ctx.exports.DynamicWorkerTail({
props: { workerId },
}),
],
}));
return worker.getEntrypoint().fetch(request);Возврат логов в реальном времени
Описанная выше настройка сохраняет логи для последующего использования, но иногда логи нужны сразу же для разработки в реальном времени. Сложность в том, что Tail Worker и loader Worker fetch() обработчики запускаются раздельно. Логи есть у Tail Worker, но у fetch() обработчик формирует ответ. Нужно общее место, куда Tail Worker может записывать логи, а fetch() обработчик может их прочитать.
A Durable Object хорошо подходит для этой задачи. И Tail Worker, и fetch() обработчик может найти тот же экземпляр Durable Object по имени. Tail Worker записывает в него логи после завершения Dynamic Worker, а fetch() обработчик считывает их и включает в ответ.
Паттерн работает следующим образом:
-
fetch()обработчик создает сессию логирования в Durable Object перед запуском Dynamic Worker. - Dynamic Worker выполняется и генерирует логи.
- После завершения работы Dynamic Worker Tail Worker записывает собранные логи в тот же Durable Object.
-
fetch()обработчик считывает логи из Durable Object и возвращает их в ответе.
import { exports } from "cloudflare:workers";
// 1. Create a log session before running the Dynamic Worker.
const logSession = exports.LogSession.getByName(workerName);
const logWaiter = await logSession.waitForLogs();
// 2. Run the Dynamic Worker.
const response = await worker.getEntrypoint().fetch(request);
// 3. Wait up to 1 second for the Tail Worker to deliver logs.
const logs = await logWaiter.getLogs(1000);Полную рабочую реализацию см. в Пример Dynamic Workers Playground ↗.