[Yandex Cloud documentation](../../index.md) > [Yandex Serverless Containers](../index.md) > [Step-by-step guides](index.md) > Managing a container > Managing logs > Writing logs

# Writing to the container execution log

{% note info %}

Logging is not free of charge. For more information, see [Yandex Cloud Logging pricing](../../logging/pricing.md).

{% endnote %}

{% list tabs group=instructions %}

- Management console {#console}
    
    1. In the [management console](https://console.yandex.cloud), select the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) with your container.
    1. Navigate to **Serverless Containers**.
    1. Select the container you want to configure logging for.
    1. Navigate to the **Editor** tab.
    1. Under **Logging**:

        1. Enable **Write logs**.
        1. In the **Destination** field, select:
                  
           * `Folder`: To write [logs](../concepts/logs.md) to the default [log group](../../logging/concepts/log-group.md) for the folder containing the container.
           * `Log group`: To write logs to a custom log group.
             
             Select the log group to write logs to or [create](../../logging/operations/create-group.md) a new one.
        
        1. Optionally, select the minimum logging level.

    1. At the top of the page, click **Create revision**. 
    
    If you set the minimum logging level, the execution log will contain logs of this level or higher. With no minimum logging level set, all container logs will be written to the execution log.

- CLI {#cli}

    If you do not have the Yandex Cloud CLI yet, [install and initialize it](../../cli/quickstart.md#install).

    The folder used by default is the one specified when [creating](../../cli/operations/profile/profile-create.md) the CLI profile. To change the default folder, use the `yc config set folder-id <folder_ID>` command. You can also specify a different folder for any command using `--folder-name` or `--folder-id`. If you access a resource by its name, the search will be limited to the default folder. If you access a resource by its ID, the search will be global, i.e., through all folders based on access permissions.

    ### Logging destination {#destination}

    If no custom [log group](../../logging/concepts/log-group.md) is specified in the container revision settings or logging remains enabled, the container automatically writes all [logs](../concepts/logs.md) to the default log group of the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) it resides in.

    To write logs to another folder's default log group, provide that folder's ID in the `--log-folder-id` parameter when [creating a container revision](manage-revision.md). The [account](../../iam/concepts/users/accounts.md) used to run the command must have the `logging.editor` [role](../../logging/security/index.md#logging-editor) or higher for the folder.

    To write logs a custom log group, provide that log group's ID in the `--log-group-id` parameter when creating a container revision. The log group may reside in a different folder. The account used to run the command must have the `logging.editor` role or higher for that folder.

    ### Minimum logging level {#log-level}

    To set the minimum logging level, specify it in the `--min-log-level` parameter when creating a container revision. 

    If you set the minimum logging level, the execution log will contain logs of this level or higher. With no minimum logging level set, all container logs will be written to the execution log.

    ### Disabling logging {#disabled}

    To disable logging, specify the `--no-logging` parameter when creating a container revision.

    ### Command example {#example}

    To write logs to a custom log group, run this command:

    ```bash
    yc serverless container revision deploy \
      --container-id <container_ID> \
      --image <Docker_image_URL> \
      --service-account-id <service_account_ID> \
      --log-folder-id <folder_ID> \
      --min-log-level <minimum_logging_level>
    ```

    Where:
    * `--container-id`: Container ID. To find out the ID, [get](list.md) the list of containers.
    * `--image`: [Docker image](../../container-registry/concepts/docker-image.md) URL.
    * `--service-account-id`: [ID of the service account](../../iam/operations/sa/get-id.md) with Docker image pull permissions.
    * `--log-group-id`: ID of the log group to write logs to.
    * `--min-log-level`: Minimum logging level. This is an optional setting.

    Result:

    ```text
    done (5s)
    id: bba9vrtrjlld********
    container_id: bbanb9mvu1dl********
    created_at: "2024-05-08T07:22:45.378Z"
    image:
      image_url: cr.yandex/crprip91p1q9********/ubuntu:hello
      image_digest: sha256:aa55c46fba9b14b8d8de16e2f8a07d716edfb1dbbb9433b827214ad2********
    resources:
      memory: "1073741824"
      cores: "1"
      core_fraction: "100"
    execution_timeout: 3s
    service_account_id: ajeh91ebakk1********
    status: ACTIVE
    log_options:
      log_group_id: e23824sf51g5********
      min_level: ERROR
    ```

- Terraform {#tf}
    
    With [Terraform](https://www.terraform.io/), you can quickly create a cloud infrastructure in Yandex Cloud and manage it using configuration files. These files store the infrastructure description written in HashiCorp Configuration Language (HCL). If you change the configuration files, Terraform automatically detects which part of your configuration is already deployed, and what should be added or removed.
    
    Terraform is distributed under the [Business Source License](https://github.com/hashicorp/terraform/blob/main/LICENSE). The [Yandex Cloud provider for Terraform](https://github.com/yandex-cloud/terraform-provider-yandex) is distributed under the [MPL-2.0](https://www.mozilla.org/en-US/MPL/2.0/) license.
    
    For more information about the provider resources, see the relevant documentation on the [Terraform](https://www.terraform.io/docs/providers/yandex/index.html) website or [its mirror](../../terraform/index.md).
    
    If you do not have Terraform yet, [install it and configure the Yandex Cloud provider](../../tutorials/infrastructure-management/terraform-quickstart.md#install-terraform).
    
    
    To manage infrastructure using Terraform under a service account or user accounts (a Yandex account, a federated account, or a local user), [authenticate](../../terraform/authentication.md) using the appropriate method.

    ### Logging destination {#destination}

    If no custom [log group](../../logging/concepts/log-group.md) is specified in the container revision settings or logging remains enabled, the container automatically writes all [logs](../concepts/logs.md) to the default log group of the [folder](../../resource-manager/concepts/resources-hierarchy.md#folder) it resides in.

    To write logs to another folder's default log group, provide that folder's ID under `log_options` in the `folder_id` parameter when [creating a container revision](manage-revision.md). The [account](../../iam/concepts/users/accounts.md) used to run the command must have the `logging.editor` [role](../../logging/security/index.md#logging-editor) or higher for the folder.

    To write logs a custom log group, provide that log group's ID under `log_options` in the `log_group_id` parameter when creating a container revision. The log group may reside in a different folder. The account used to run the command must have the `logging.editor` role or higher for that folder.

    ### Minimum logging level {#log-level}

    To set the minimum logging level, specify it under `log_options` in the `min_level` parameter when creating a container revision. 

    If you set the minimum logging level, the execution log will contain logs of this level or higher. With no minimum logging level set, all container logs will be written to the execution log.

    ### Disabling logging {#disabled}

    To disable logging, specify `disabled` set to `true` under `log_options` when creating a container revision.

    ### Example {#example}

    To write logs to a custom log group:

    1. Open the Terraform configuration file and add the `log_options` section to the `yandex_serverless_container` resource description:

        Here is an example of the configuration file structure:
        
        ```hcl
        resource "yandex_serverless_container" "<container_name>" {
          name               = "<container_name>"
          service_account_id = "<service_account_ID>"
          memory             = <RAM_amount>
          image {
            url = "<Docker_image_URL>"
          }
          log_options {
            folder_id = "<folder_ID>"
            min_level = "<minimum_logging_level>"
          }
        }
        ```

        Where:
        * `name`: Container name.
        * `service_account_id`: [ID of the service account](../../iam/operations/sa/get-id.md) with Docker image pull permissions.
        * `memory`: Required memory. The default value is 128 MB.
        * `image`: Docker image settings:
            * `url`: [Docker image](../../container-registry/concepts/docker-image.md) URL.
        * `log_options`: Logging settings:
            * `folder_id`: Folder ID.
            * `min_level`: Minimum logging level. This is an optional setting.

        For more information about `yandex_serverless_container` properties, see [this provider guide](../../terraform/resources/serverless_container.md).

    1. Create the resources:

        1. In the terminal, navigate to the configuration file directory.
        1. Make sure the configuration is correct using this command:
        
           ```bash
           terraform validate
           ```
        
           If the configuration is valid, you will get this message:
        
           ```bash
           Success! The configuration is valid.
           ```
        
        1. Run this command:
        
           ```bash
           terraform plan
           ```
        
           You will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
        1. Apply the configuration changes:
        
           ```bash
           terraform apply
           ```
        
        1. Type `yes` and press **Enter** to confirm the changes.

 - API {#api}

    To write logs to the container execution log, use the [deployRevision](../containers/api-ref/Container/deployRevision.md) REST API method for the [Container](../containers/api-ref/Container/index.md) resource or the [ContainerService/DeployRevision](../containers/api-ref/grpc/Container/deployRevision.md) gRPC API call.

{% endlist %}

## Structured logs {#structured-logs}

Apart from text, you can write [structured logs](../concepts/logs.md#structured-logs) to the standard output (`stdout`) and standard error output (`stderr`).

### Applications and Dockerfile examples

{% list tabs group=programming_language %}

- Node.js {#node}

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

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

    const app = express();
    app.use(express.urlencoded({ extended: true }));
    app.use(express.json());

    app.get("/", (req, res) => {
        logger.info({"message": "My log message", "my-key": "my-value"})
        return res.send("Hello, world!");
    });

    app.listen(process.env.PORT);
    ```

    **Dockerfile**
    ```dockerfile
    FROM node:16-slim

    WORKDIR /app
    RUN npm install winston express
    COPY ./index.js .

    CMD [ "node", "index.js" ]
    ```

- Python {#python}

    **requirements.txt**
    ```text
    python-json-logger==2.0.4
    sanic==22.12.0
    ```

    **index.py**
  
    ```python
    import logging
    import os

    from pythonjsonlogger import jsonlogger
    from sanic import Sanic
    from sanic.response import text


    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")


    app = Sanic(__name__)

    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)


    @app.route("/")
    async def hello(request):
        logger.info("My log message", extra={"my-key": "my-value"})
        return text("Hello, world!", status=200)


    if __name__ == "__main__":
        app.run(host='0.0.0.0', port=int(os.environ['PORT']), motd=False, access_log=False)
    ```

    **Dockerfile**
    ```dockerfile
    FROM python:3.10-slim

    WORKDIR /app
    COPY ./index.py .
    COPY ./requirements.txt .
    RUN pip install --no-cache-dir --prefer-binary --requirement=./requirements.txt

    CMD [ "python", "index.py" ]
    ```

- Go {#go}

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

    import (
        "go.uber.org/zap"
        "net/http"
        "os"
    )

    func main() {
        zapConfig := zap.NewProductionConfig()
        zapConfig.DisableCaller = true
        zapConfig.Level.SetLevel(zap.DebugLevel)
        logger, _ := zapConfig.Build()

        portStr := os.Getenv("PORT")
        http.Handle("/", handler{logger})
        http.ListenAndServe(":"+portStr, nil)
    }

    type handler struct {
        logger *zap.Logger
    }

    func (h handler) ServeHTTP(writer http.ResponseWriter, _ *http.Request) {
        h.logger.Info(
            "My log message",
            zap.String("my-key", "my-value"),
        )

        writer.WriteHeader(200)
        _, _ = writer.Write([]byte("Hello, world!"))
    }
    ```

    **Dockerfile**
    ```dockerfile
    FROM golang:latest AS build

    WORKDIR /app
    ADD index.go .
    ADD go.mod .
    ADD go.sum .
    RUN go build -a -tags netgo -ldflags '-w -extldflags "-static"' -o server-app *.go

    FROM scratch
    COPY --from=build /app/server-app /server-app

    ENTRYPOINT ["/server-app"]
    ```

{% endlist %}