> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gcore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Configure cluster logging

export const MethodSection = ({children}) => children ?? null;

export const MethodSwitch = ({children}) => {
  const tabs = React.Children.toArray(children).map(c => {
    if (!c || !c.props) return null;
    if (c.props.id) return c;
    const inner = c.props.children;
    if (inner && inner.props && inner.props.id) return inner;
    return null;
  }).filter(Boolean);
  const firstId = tabs.length > 0 ? tabs[0].props.id : "";
  const [active, setActive] = React.useState(firstId);
  React.useEffect(() => {
    try {
      const saved = localStorage.getItem("gcore_docs_method");
      if (saved && tabs.find(t => t.props.id === saved)) {
        setActive(saved);
      }
    } catch (_) {}
  }, []);
  React.useEffect(() => {
    try {
      document.querySelectorAll("h2[id], h3[id]").forEach(heading => {
        const visible = heading.offsetParent !== null;
        document.querySelectorAll(`a[href="#${heading.id}"]`).forEach(link => {
          if (link.closest("h1,h2,h3,h4,h5,h6")) return;
          const li = link.closest("li");
          if (li) li.style.display = visible ? "" : "none";
        });
      });
    } catch (_) {}
    window.dispatchEvent(new Event("scroll"));
  }, [active]);
  const handleClick = id => {
    setActive(id);
    try {
      localStorage.setItem("gcore_docs_method", id);
    } catch (_) {}
  };
  return <div>
      <div className="not-prose flex gap-0 border-b border-zinc-200 dark:border-zinc-800 mb-8 mt-2" role="tablist">
        {tabs.map(tab => {
    const isActive = active === tab.props.id;
    return <button key={tab.props.id} role="tab" aria-selected={isActive} onClick={() => handleClick(tab.props.id)} className={["px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors cursor-pointer", isActive ? "border-primary text-primary" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"].join(" ")}>
              {tab.props.label}
            </button>;
  })}
      </div>

      {tabs.map(tab => <div key={tab.props.id} style={{
    display: active === tab.props.id ? "" : "none"
  }}>
          {tab.props.children}
        </div>)}
    </div>;
};

<MethodSwitch>
  <MethodSection id="portal" label="Customer Portal">
    <p>Cluster logging collects container and system logs, storing them in OpenSearch Dashboards for analysis and debugging. Logging is a paid feature.</p>

    <Steps>
      <Step title="Open the cluster">
        <Frame>
          <img src="https://mintcdn.com/gcore/c2W3cwtGjSbFG_V1/images/docs/edge-ai/managed-kubernetes/configure-cluster-logging/configure-cluster-logging-image1.png?fit=max&auto=format&n=c2W3cwtGjSbFG_V1&q=85&s=85ded34b923f5d56a0afac1101b5a026" alt="Kubernetes Clusters list with doc-k8s-test cluster in Provisioned status" width="1024" height="327" data-path="images/docs/edge-ai/managed-kubernetes/configure-cluster-logging/configure-cluster-logging-image1.png" />
        </Frame>
      </Step>

      <Step title="Navigate to the Logging tab">
        <Frame>
          <img src="https://mintcdn.com/gcore/c2W3cwtGjSbFG_V1/images/docs/edge-ai/managed-kubernetes/configure-cluster-logging/configure-cluster-logging-image2.png?fit=max&auto=format&n=c2W3cwtGjSbFG_V1&q=85&s=42e9dd90c6fb8491d681987e736b6177" alt="Cluster detail page with the Logging tab highlighted" width="1024" height="271" data-path="images/docs/edge-ai/managed-kubernetes/configure-cluster-logging/configure-cluster-logging-image2.png" />
        </Frame>
      </Step>

      <Step title="Toggle Enable Logging" />

      <Step title="Select a log topic">
        Select an existing log topic or create a new one.
      </Step>

      <Step title="Click Save" />
    </Steps>
  </MethodSection>

  <MethodSection id="api" label="REST API">
    <p>Cluster logging forwards container and system logs to Gcore Logging-as-a-Service (LaaS), where they are stored in OpenSearch Dashboards. Logging requires a destination region — a Gcore region that hosts a LaaS instance — which may differ from the cluster region.</p>

    <Info>
      An [API token](/account-settings/api-tokens) is required, along with a
      [project ID](/api-reference/cloud/projects/list-projects)
      and a [region ID](/api-reference/cloud/regions/list-regions).
    </Info>

    <p>Set the following environment variables before running the examples:</p>

    ```bash theme={null}
    export GCORE_API_KEY="{YOUR_API_KEY}"
    export GCORE_CLOUD_PROJECT_ID="{YOUR_PROJECT_ID}"
    export GCORE_CLOUD_REGION_ID="{YOUR_REGION_ID}"
    export CLUSTER_NAME="{YOUR_CLUSTER_NAME}"
    ```

    ## List available destination regions

    <p>Each cluster region has a set of LaaS destination regions where logs can be forwarded. Retrieve the list before enabling logging to get the correct `destination_region_id`.</p>

    ```bash theme={null}
    curl "https://api.gcore.com/cloud/v1/laas/$GCORE_CLOUD_REGION_ID/destination_regions" \
      -H "Authorization: APIKey $GCORE_API_KEY"
    ```

    <p>The API returns:</p>

    ```json theme={null}
    {
      "count": 1,
      "results": [
        {
          "region_id": 76,
          "region_name": "Luxembourg-2"
        }
      ]
    }
    ```

    <p>Use the `region_id` from this response as `destination_region_id` in the enable call below.</p>

    ## Enable logging

    <p>Pass the destination region, a topic name, and an optional retention period. The topic is created automatically if it does not exist.</p>

    | Field                     | Required | Description                               |
    | ------------------------- | -------- | ----------------------------------------- |
    | `enabled`                 | Yes      | Set to `true` to start log forwarding     |
    | `destination_region_id`   | Yes      | LaaS region from the list above           |
    | `topic_name`              | No       | Topic to write logs to; created if absent |
    | `retention_policy.period` | No       | Log retention in days                     |

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import os
        import time
        import gcore

        client = gcore.Gcore(api_key=os.environ["GCORE_API_KEY"])
        project_id = int(os.environ["GCORE_CLOUD_PROJECT_ID"])
        region_id = int(os.environ["GCORE_CLOUD_REGION_ID"])
        cluster_name = os.environ["CLUSTER_NAME"]

        result = client.cloud.k8s.clusters.update(
            cluster_name=cluster_name,
            project_id=project_id,
            region_id=region_id,
            logging={
                "enabled": True,
                "destination_region_id": 76,  # from the destination regions list
                "topic_name": "my-cluster-logs",
                "retention_policy": {"period": 30},
            },
        )

        task_id = result.tasks[0]
        while True:
            task = client.cloud.tasks.get(task_id)
            if task.state in ("FINISHED", "ERROR"):
                break
            time.sleep(5)

        print("Logging enabled:", task.state)
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "os"
            "strconv"
            "time"

            gcore "github.com/G-Core/gcore-go"
            "github.com/G-Core/gcore-go/cloud"
            "github.com/G-Core/gcore-go/option"
        )

        func main() {
            projectID, _ := strconv.ParseInt(os.Getenv("GCORE_CLOUD_PROJECT_ID"), 10, 64)
            regionID, _ := strconv.ParseInt(os.Getenv("GCORE_CLOUD_REGION_ID"), 10, 64)
            clusterName := os.Getenv("CLUSTER_NAME")

            client := gcore.NewClient(option.WithAPIKey(os.Getenv("GCORE_API_KEY")))
            ctx := context.TODO()

            result, err := client.Cloud.K8S.Clusters.Update(ctx, clusterName, cloud.K8SClusterUpdateParams{
                ProjectID: gcore.Int(projectID),
                RegionID:  gcore.Int(regionID),
                Logging: cloud.K8SClusterUpdateParamsLogging{
                    Enabled:             gcore.Bool(true),
                    DestinationRegionID: gcore.Int(76), // from the destination regions list
                    TopicName:           gcore.String("my-cluster-logs"),
                    RetentionPolicy: cloud.LaasIndexRetentionPolicyParam{
                        Period: gcore.Int(30),
                    },
                },
            })
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }

            taskID := result.Tasks[0]
            for {
                task, _ := client.Cloud.Tasks.Get(ctx, taskID)
                if task.State == "FINISHED" || task.State == "ERROR" {
                    fmt.Println("Logging enabled:", task.State)
                    break
                }
                time.Sleep(5 * time.Second)
            }
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X PATCH "https://api.gcore.com/cloud/v2/k8s/clusters/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$CLUSTER_NAME" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{
            "logging": {
              "enabled": true,
              "destination_region_id": 76,
              "topic_name": "my-cluster-logs",
              "retention_policy": {"period": 30}
            }
          }'
        ```

        Response:

        ```json theme={null}
        {"tasks": ["84162eb4-2555-4348-bead-dbc0c578d2de"]}
        ```
      </Tab>
    </Tabs>

    <p>The API returns a task ID. Poll <code>GET /cloud/v1/tasks/{task_id}</code> every five seconds until `state` is `FINISHED`.</p>

    ## Disable logging

    <p>Set `enabled` to `false` to stop log forwarding. The existing log topic and its data are preserved in OpenSearch Dashboards.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import os
        import time
        import gcore

        client = gcore.Gcore(api_key=os.environ["GCORE_API_KEY"])
        project_id = int(os.environ["GCORE_CLOUD_PROJECT_ID"])
        region_id = int(os.environ["GCORE_CLOUD_REGION_ID"])
        cluster_name = os.environ["CLUSTER_NAME"]

        result = client.cloud.k8s.clusters.update(
            cluster_name=cluster_name,
            project_id=project_id,
            region_id=region_id,
            logging={"enabled": False},
        )

        task_id = result.tasks[0]
        while True:
            task = client.cloud.tasks.get(task_id)
            if task.state in ("FINISHED", "ERROR"):
                break
            time.sleep(5)

        print("Logging disabled:", task.state)
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "os"
            "strconv"
            "time"

            gcore "github.com/G-Core/gcore-go"
            "github.com/G-Core/gcore-go/cloud"
            "github.com/G-Core/gcore-go/option"
        )

        func main() {
            projectID, _ := strconv.ParseInt(os.Getenv("GCORE_CLOUD_PROJECT_ID"), 10, 64)
            regionID, _ := strconv.ParseInt(os.Getenv("GCORE_CLOUD_REGION_ID"), 10, 64)
            clusterName := os.Getenv("CLUSTER_NAME")

            client := gcore.NewClient(option.WithAPIKey(os.Getenv("GCORE_API_KEY")))
            ctx := context.TODO()

            result, err := client.Cloud.K8S.Clusters.Update(ctx, clusterName, cloud.K8SClusterUpdateParams{
                ProjectID: gcore.Int(projectID),
                RegionID:  gcore.Int(regionID),
                Logging: cloud.K8SClusterUpdateParamsLogging{
                    Enabled: gcore.Bool(false),
                },
            })
            if err != nil {
                fmt.Fprintln(os.Stderr, err)
                os.Exit(1)
            }

            taskID := result.Tasks[0]
            for {
                task, _ := client.Cloud.Tasks.Get(ctx, taskID)
                if task.State == "FINISHED" || task.State == "ERROR" {
                    fmt.Println("Logging disabled:", task.State)
                    break
                }
                time.Sleep(5 * time.Second)
            }
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X PATCH "https://api.gcore.com/cloud/v2/k8s/clusters/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$CLUSTER_NAME" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{"logging": {"enabled": false}}'
        ```

        Response:

        ```json theme={null}
        {"tasks": ["task-uuid"]}
        ```
      </Tab>
    </Tabs>

    <p>The API returns a task ID. Poll <code>GET /cloud/v1/tasks/{task_id}</code> every five seconds until `state` is `FINISHED`.</p>
  </MethodSection>
</MethodSwitch>
