[Документация Yandex Cloud](../../../index.md) > [Yandex Cloud Functions](../../index.md) > [Пошаговые инструкции](../index.md) > Управление функцией > Управлять логами > Записать логи

# Записать логи в журнал выполнения функции

{% note info %}

Логирование тарифицируется. Подробнее в [документации Yandex Cloud Logging](../../../logging/pricing.md).

{% endnote %}

{% list tabs group=instructions %}

- Консоль управления {#console}
    
    1. В [консоли управления](https://console.yandex.cloud) перейдите в [каталог](../../../resource-manager/concepts/resources-hierarchy.md#folder), в котором находится функция.
    1. Перейдите в сервис **Cloud Functions**.
    1. Выберите функцию, для которой хотите настроить логирование.
    1. Перейдите на вкладку **Редактор**.
    1. В блоке **Логирование**:
        
        1. Включите опцию **Запись логов**.
        1. В поле **Назначение** выберите:
          
           * `Каталог` — чтобы записывать [логи](../../concepts/logs.md) в [лог-группу](../../../logging/concepts/log-group.md) по умолчанию для каталога, в котором находится функция.
           * `Лог-группа` — чтобы записывать логи в пользовательскую лог-группу.
             
             Выберите лог-группу, в которую будут записываться логи, или [создайте](../../../logging/operations/create-group.md) новую.

        1. (Опционально) Выберите минимальный уровень логирования.

    1. Нажмите кнопку **Сохранить изменения**. 
    
    Если минимальный уровень логирования задан, в журнал выполнения записываются логи указанного уровня и выше. Если минимальный уровень логирования не задан, в журнал выполнения записываются все логи функции.

- CLI {#cli}

    Если у вас еще нет интерфейса командной строки Yandex Cloud (CLI), [установите и инициализируйте его](../../../cli/quickstart.md#install).

    По умолчанию используется каталог, указанный при [создании](../../../cli/operations/profile/profile-create.md) профиля CLI. Чтобы изменить каталог по умолчанию, используйте команду `yc config set folder-id <идентификатор_каталога>`. Также для любой команды вы можете указать другой каталог с помощью параметров `--folder-name` или `--folder-id`. Если вы обращаетесь к ресурсу по имени, поиск будет выполнен в каталоге по умолчанию. Если вы обращаетесь к ресурсу по идентификатору, поиск будет выполнен глобально — во всех каталогах с учетом прав доступа.

    ### Назначение логирования {#destination}

    Если в параметрах версии функции не указана пользовательская [лог-группа](../../../logging/concepts/log-group.md) или логирование не отключено, функция автоматически пишет все [логи](../../concepts/logs.md) в лог-группу по умолчанию для [каталога](../../../resource-manager/concepts/resources-hierarchy.md#folder), в котором она находится.

    Чтобы записывать логи в лог-группу по умолчанию для другого каталога, укажите идентификатор этого каталога в параметре `--log-folder-id` при [создании версии функции](version-manage.md). [Аккаунту](../../../iam/concepts/users/accounts.md), от имени которого выполняется команда, на этот каталог должна быть назначена [роль](../../../logging/security/index.md#logging-editor) `logging.editor` или выше.

    Чтобы записывать логи в пользовательскую лог-группу, укажите идентификатор этой лог-группы в параметре `--log-group-id` при создании версии функции. Лог-группа может находиться в другом каталоге. Аккаунту, от имени которого выполняется команда, на этот каталог должна быть назначена роль `logging.editor` или выше.


    ### Минимальный уровень логирования {#log-level}

    Чтобы задать минимальный уровень логирования, укажите его в параметре `--min-log-level` при создании версии функции. 
    
    Если минимальный уровень логирования задан, в журнал выполнения записываются логи указанного уровня и выше. Если минимальный уровень логирования не задан, в журнал выполнения записываются все логи функции.

    ### Отключение логирования {#disabled}

    Чтобы отключить логирование, при создании версии функции укажите параметр `--no-logging`.

    ### Пример команды {#example}
    
    Чтобы записывать логи в пользовательскую лог-группу, выполните команду:
        
    ```
    yc serverless function version create \
      --function-id <идентификатор_функции> \
      --runtime <среда_выполнения> \
      --entrypoint <точка_входа> \
      --memory <объем_RAM> \
      --source-path <ZIP-архив_c_кодом_функции> \
      --log-group-id <идентификатор_лог-группы> \
      --min-log-level <минимальный_уровень_логирования>
    ```

    Где:
    * `--function-id` — идентификатор функции.
    * `--runtime` — среда выполнения.
    * `--entrypoint` — точка входа, указывается в формате `<имя_файла_без_расширения>.<имя_обработчика>`.
    * `--memory` — объем RAM.
    * `--source-path` — ZIP-архив c кодом функции и необходимыми зависимостями.
    * `--log-group-id` — идентификатор лог-группы, в которую будут записываться логи.
    * `--min-log-level` — минимальный уровень логирования. Необязательный параметр.

    Результат:
    ```
    done (4s)
    id: d4ech7qdki6r********
    function_id: d4e7tbg7m4np********
    created_at: "2024-04-19T10:13:00.019Z"
    runtime: python37
    entrypoint: index.handler
    resources:
      memory: "134217728"
    execution_timeout: 5s
    image_size: "53248"
    status: ACTIVE
    tags:
      - $latest
    log_options:
      log_group_id: e23u2vn449av********
      min_level: DEBUG
    ```

- Terraform {#tf}
    
    [Terraform](https://www.terraform.io/) позволяет быстро создать облачную инфраструктуру в Yandex Cloud и управлять ею с помощью файлов конфигураций. В файлах конфигураций хранится описание инфраструктуры на языке HCL (HashiCorp Configuration Language). При изменении файлов конфигураций Terraform автоматически определяет, какая часть вашей конфигурации уже развернута, что следует добавить или удалить.
    
    Terraform распространяется под лицензией [Business Source License](https://github.com/hashicorp/terraform/blob/main/LICENSE), а [провайдер Yandex Cloud для Terraform](https://github.com/yandex-cloud/terraform-provider-yandex) — под лицензией [MPL-2.0](https://www.mozilla.org/en-US/MPL/2.0/).
    
    Подробная информация о ресурсах провайдера в документации на сайте [Terraform](https://www.terraform.io/docs/providers/yandex/index.html) или в [зеркале](../../../terraform/index.md).
    
    Если у вас еще нет Terraform, [установите его и настройте провайдер Yandex Cloud](../../../tutorials/infrastructure-management/terraform-quickstart.md#install-terraform).
    
    
    Чтобы управлять инфраструктурой с помощью Terraform от имени сервисного аккаунта или пользовательских аккаунтов: аккаунта на Яндексе, федеративного аккаунта и локального пользователя, [аутентифицируйтесь](../../../terraform/authentication.md) соответствующим способом.

    ### Назначение логирования {#destination}

    Если в параметрах версии функции не указана пользовательская [лог-группа](../../../logging/concepts/log-group.md) или логирование не отключено, функция автоматически пишет все [логи](../../concepts/logs.md) в лог-группу по умолчанию для [каталога](../../../resource-manager/concepts/resources-hierarchy.md#folder), в котором она находится.

    Чтобы записывать логи в лог-группу по умолчанию для другого каталога, укажите идентификатор этого каталога в блоке `log_options` в параметре `folder_id` при [создании версии функции](version-manage.md). [Аккаунту](../../../iam/concepts/users/accounts.md), от имени которого выполняется команда, на этот каталог должна быть назначена [роль](../../../logging/security/index.md#logging-editor) `logging.editor` или выше.

    Чтобы записывать логи в пользовательскую лог-группу, укажите идентификатор этой лог-группы в блоке `log_options` в параметре `log_group_id` при создании версии функции. Лог-группа может находиться в другом каталоге. Аккаунту, от имени которого выполняется команда, на этот каталог должна быть назначена роль `logging.editor` или выше.

    ### Минимальный уровень логирования {#log-level}

    Чтобы задать минимальный уровень логирования, укажите его в блоке `log_options`  в параметре `min_level` при создании версии функции.

    Если минимальный уровень логирования задан, в журнал выполнения записываются логи указанного уровня и выше. Если минимальный уровень логирования не задан, в журнал выполнения записываются все логи функции.

    ### Отключение логирования {#disabled}

    Чтобы отключить логирование, при создании версии функции в блоке `log_options` укажите параметр `disabled` со значением `true`.

    ### Пример {#example}

    Чтобы записывать логи в пользовательскую лог-группу:

    1. Откройте файл конфигурации Terraform и добавьте к описанию ресурса `yandex_function` блок `log_options`:

        Примеры структуры конфигурационного файла:

        ```hcl
        resource "yandex_function" "my-function" {
          name       = "<имя_функции>"
          user_hash  = "<хeш_версии_функции>"
          runtime    = "<среда_выполнения>"
          entrypoint = "<точка_входа>"
          memory     = "<объем_RAM>"
          content {
            zip_filename = "<путь_к_ZIP-архиву>"
          }
          log_options {
            log_group_id = "<идентификатор_лог-группы>"
            min_level    = "<минимальный_уровень_логирования>"
          }
        }
        ```

        Где:
        * `name` — имя функции.
        * `user_hash` — произвольная строка, определяющая версию функции. При изменениях функции необходимо менять и эту строку. Функция обновится при изменении этой строки.
        * `runtime` — [среда выполнения](../../concepts/runtime/index.md) функции.
        * `entrypoint` — имя функции в исходном коде, которая будет служить точкой входа в приложения.
        * `memory` — объем памяти в мегабайтах, отведенный для выполнения функции.
        * `content` — исходный код функции:
            * `zip_filename` — путь к ZIP-архиву, содержащему исходный код функции и необходимые зависимости.
        * `log_options` — настройки логирования:
            * `log_group_id` — идентификатор лог-группы, в которую будут записываться логи.
            * `min_level` — минимальный уровень логирования. Необязательный параметр.

        Подробнее о параметрах ресурса `yandex_function` в [документации провайдера](../../../terraform/resources/function.md).

    1. Примените изменения:

        1. В терминале перейдите в директорию с конфигурационным файлом.
        1. Проверьте корректность конфигурации с помощью команды:
        
           ```bash
           terraform validate
           ```
        
           Если конфигурация является корректной, появится сообщение:
        
           ```bash
           Success! The configuration is valid.
           ```
        
        1. Выполните команду:
        
           ```bash
           terraform plan
           ```
        
           В терминале будет выведен список ресурсов с параметрами. На этом этапе изменения не будут внесены. Если в конфигурации есть ошибки, Terraform на них укажет.
        1. Примените изменения конфигурации:
        
           ```bash
           terraform apply
           ```
        
        1. Подтвердите изменения: введите в терминале слово `yes` и нажмите **Enter**.

- API {#api}

    Чтобы записывать логи в журнал выполнения функции, воспользуйтесь методом REST API [createVersion](../../functions/api-ref/Function/createVersion.md) для ресурса [Function](../../functions/api-ref/Function/index.md) или вызовом gRPC API [FunctionService/LogOptions](../../functions/api-ref/grpc/Function/createVersion.md#yandex.cloud.serverless.functions.v1.LogOptions).

{% endlist %}

## Структурированные логи {#structured-logs}

Кроме текстовых записей, в стандартный поток вывода (`stdout`) и стандартный поток вывода ошибок (`stderr`) можно писать [структурированные логи](../../concepts/logs.md#structured-logs).

### Примеры функций

{% list tabs group=programming_language %}

- Node.js {#node}

    **package.json**
    ```json
    {
      "name": "server-app",
      "version": "1.0.0",
      "dependencies": {
        "winston": "^3.8.2"
      }
    }
    ```

    **index.js**
    ```js
    const winston = require('winston');

    const logger = winston.createLogger({
        level: 'debug',
        format: winston.format.json(),
        transports: [new winston.transports.Console()],
    });

    module.exports.handler = async function (event, context) {
        logger.info({"message": "My log message", "my-key": "my-value"})
        return {
            statusCode: 200,
            body: 'Hello World!',
        };
    };
    ```

- Python {#python}

    **requirements.txt**
    ```
    python-json-logger==2.0.4

    ```

    **index.py**
    ```python
    import logging
    from pythonjsonlogger import jsonlogger


    class YcLoggingFormatter(jsonlogger.JsonFormatter):
        def add_fields(self, log_record, record, message_dict):
            super(YcLoggingFormatter, self).add_fields(log_record, record, message_dict)
            log_record['logger'] = record.name
            log_record['level'] = str.replace(str.replace(record.levelname, "WARNING", "WARN"), "CRITICAL", "FATAL")

    logHandler = logging.StreamHandler()
    logHandler.setFormatter(YcLoggingFormatter('%(message)s %(level)s %(logger)s'))

    logger = logging.getLogger('MyLogger')
    logger.propagate = False
    logger.addHandler(logHandler)
    logger.setLevel(logging.DEBUG)

    def handler(event, context):
        logger.info("My log message", extra={"my-key": "my-value"})
        
        return "Hello, world!"
    ```
- Go {#go}

    **index.go**
    ```go
    package main

    import (
        "context"
        "go.uber.org/zap"
    )

    type Response struct {
        StatusCode int         `json:"statusCode"`
        Body       interface{} `json:"body"`
    }

    func Handler(ctx context.Context) (*Response, error) {
        config := zap.NewProductionConfig()
        config.DisableCaller = true
        config.Level.SetLevel(zap.DebugLevel)
        logger, _ := config.Build()
        defer logger.Sync()

        logger.Info(
            "My log message",
            zap.String("my-key", "my-value"),
        )

        return &Response{
            StatusCode: 200,
            Body:       "Hello, world!",
        }, nil
    }
    ```

- Java {#java}

    **pom.xml**
    ```xml
    ...
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.19.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.19.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-layout-template-json</artifactId>
        <version>2.19.0</version>
    </dependency>
    ...
    ```

    **log4j2.xml**
    ```xml
    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration>
        <Appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <JsonTemplateLayout eventTemplateUri="classpath:YcLoggingLayout.json"/>
            </Console>
        </Appenders>
        <Loggers>
            <Root level="TRACE">
                <AppenderRef ref="Console"/>
            </Root>
        </Loggers>
    </Configuration>
    ```

    **YcLoggingLayout.json**
    ```json
    {
      "message": {
        "$resolver": "message",
        "stringified": true
      },
      "level": {
        "$resolver": "level",
        "field": "name"
      },
      "logger": {
        "$resolver": "logger",
        "field": "name"
      },
      "labels": {
        "$resolver": "mdc",
        "flatten": true,
        "stringified": true
      },
      "tags": {
        "$resolver": "ndc"
      }
    }
    ```

    **Handler.java**
    ```java
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.apache.logging.log4j.ThreadContext;

    import java.util.function.Function;

    public class Handler implements Function<String, String> {

        private static final Logger logger = LogManager.getLogger();

        @Override
        public String apply(String s) {
            ThreadContext.put("my-key", "my-value");
            logger.info("My log message");
            ThreadContext.clearAll();
            return "Hello, world!";
        }
    }
    ```

{% endlist %}