Skip to content

View logs

This guide explains how to find and use RelationalAI Native App logs in Snowflake, including how to share filtered logs with RelationalAI support when deeper diagnostics are needed for a specific incident or time window.

  • The RAI Native App is installed in your Snowflake account.
  • You can create and run Snowflake Notebooks in Snowsight.
  • You can use the ACCOUNTADMIN role in Snowflake for the log-sharing workflow.

The RAI Native App writes information to different Snowflake surfaces:

LocationWhat it is used for
Active Snowflake Event TableContinuous app telemetry and observability metrics. This is the main source for routine monitoring.
RELATIONALAI.LOGGING.LOGSInternal application log records. This table gives you direct access to recent log entries, but it is not intended for end-user consumption and should be treated as potentially sensitive operational data.
RELATIONALAI.APP_STATE.CLIENT_LOG_STAGEFiltered support-share files used when RelationalAI asks for deeper diagnostics. See Share logs with RelationalAI support for details.

You do not need to query these surfaces directly for routine monitoring or troubleshooting. Refer to the following resources for observability and monitoring guidance.

The Native App collects different kinds of operational data for different purposes: Event Table telemetry gives you high-level health and usage signals for monitoring, LOGGING.LOGS contains raw internal log messages and metadata for deeper diagnosis, and the support-share workflow produces a filtered subset of engine and optional control-plane logs for a specific incident or time window.

Use on-demand logs when RelationalAI asks for deeper diagnostics for a specific time window, engine, or incident. This workflow shares a filtered set of staged logs instead of exposing your full telemetry history.

Do the following to create the secure share and copy the requested logs:

  1. Download and import the notebook into Snowflake

    Download the on-demand logs notebook.

    In Snowsight, choose + Create Projects > Notebook > Import .ipynb File, then upload the notebook. If you want to inspect the workflow before importing it, use the embedded preview below.

    View a preview of the notebook.

    Sharing On-Demand Logs with RAI

    Overview

    This notebook creates and shares a secure-share view with RAI to provide access to on-demand logs. It’s designed to run as a Snowflake Notebook, but it can be adapted to run as a local Jupyter notebook by replacing the call to get_active_session() with code to generate a Session object locally. See Snowflake’s documentation for details.

    from datetime import datetime, timedelta, date
    def get_date_range(start_date, end_date):
    start = datetime.strptime(start_date, "%Y-%m-%d")
    end = datetime.strptime(end_date, "%Y-%m-%d")
    dates = [(start + timedelta(days=i)).strftime("%Y-%m-%d")
    for i in range((end - start).days + 1)]
    return "|".join(dates)

    Edit this cell with your specific values:

    # Override this to the date you want to get logs starting from in the format YYYY-MM-DD:
    start_date = date.today().strftime("%Y-%m-%d")
    # Override this to the date you want to get logs until in the format YYYY-MM-DD
    end_date = date.today().strftime("%Y-%m-%d")
    date_range = get_date_range(start_date, end_date)
    # Override this to True if you want to share spcs_control_plane logs
    include_erps_logs = False
    # Override this to the engine name (ex, 'testEngine') or leave it as it is if you want to get logs for all engines
    engine_name = ".*"
    warehouse = ""
    # Override this to a unique id and share it with RAI
    id = ""
    # The account you want to share the logs with -- it should be in the format org.account_name
    event_sharing_account = ""
    # Your native app name (usually relationalai)
    native_app_name = "relationalai"
    engine_file_pattern = f'{engine_name}/clientlogs-.*({date_range}).*\\.json|{engine_name}/clientlogs-engine.json'
    erp_file_pattern = f'|clientlogs-cp-({date_range}).*\\.json|.*clientlogs-cp.json'
    if include_erps_logs:
    file_pattern = f'.*({engine_file_pattern}{erp_file_pattern}).*'
    else:
    file_pattern = f'.*({engine_file_pattern}).*'
    sql_query = """
    BEGIN
    USE ROLE ACCOUNTADMIN;
    USE WAREHOUSE &warehouse; -- Update to use another warehouse if necessary.
    CREATE DATABASE IF NOT EXISTS TELEMETRY_SHARING;
    USE DATABASE TELEMETRY_SHARING;
    CREATE SCHEMA IF NOT EXISTS LOGS;
    USE SCHEMA LOGS;
    --*****--
    -- Load staged data files to temporary tables
    --*****--
    CREATE OR REPLACE TABLE TELEMETRY_SHARING.LOGS.TELEMETRY_LOAD_TABLE_&id (
    LOG_RECORD VARCHAR
    );
    CREATE OR REPLACE TABLE TELEMETRY_SHARING.LOGS.TELEMETRY_SHARE_TABLE_&id (
    TIMESTAMP TIMESTAMP,
    OBSERVED_TIMESTAMP TIMESTAMP,
    SPAN_ID VARCHAR,
    TRACE_ID VARCHAR,
    MESSAGE VARCHAR,
    LOG_RECORD VARCHAR
    );
    --*****--
    -- Create secure view from table with target log records
    --*****--
    CREATE OR REPLACE SECURE VIEW TELEMETRY_SHARING.LOGS.TELEMETRY_SHARE_VIEW_&id
    COMMENT = 'View containing telemetry records to share with the RAI provider account'
    AS
    SELECT *
    FROM TELEMETRY_SHARING.LOGS.TELEMETRY_SHARE_TABLE_&id ;
    --*****--
    -- Share secure view with the RAI provider account
    --*****--
    CREATE OR REPLACE SHARE TELEMETRY_SHARE_&id;
    CREATE DATABASE ROLE IF NOT EXISTS TELEMETRY_SHARE_ROLE;
    GRANT USAGE ON DATABASE TELEMETRY_SHARING TO SHARE TELEMETRY_SHARE_&id;
    GRANT USAGE ON SCHEMA TELEMETRY_SHARING.LOGS TO DATABASE ROLE TELEMETRY_SHARE_ROLE;
    GRANT SELECT ON VIEW TELEMETRY_SHARE_VIEW_&id TO DATABASE ROLE TELEMETRY_SHARE_ROLE;
    GRANT DATABASE ROLE TELEMETRY_SHARE_ROLE TO SHARE TELEMETRY_SHARE_&id;
    ALTER SHARE TELEMETRY_SHARE_&id ADD ACCOUNTS = &event_sharing_account;
    COPY INTO TELEMETRY_SHARING.LOGS.TELEMETRY_LOAD_TABLE_&id
    FROM (
    SELECT
    $1 AS log_record
    FROM @&native_app_name.app_state.client_log_stage
    )
    PATTERN = '&file_pattern'
    FILE_FORMAT = (TYPE = JSON)
    ON_ERROR = CONTINUE; -- This will skip any log records that are invalid JSON.
    -- The output of the query will indicate if any records were skipped due to errors.
    -- Copy from TELEMETRY_LOAD_TABLE_&id into TELEMETRY_SHARE_TABLE_&id and remove safe logs
    INSERT INTO TELEMETRY_SHARING.LOGS.TELEMETRY_SHARE_TABLE_&id
    SELECT
    to_timestamp(timeUnixNano) as timestamp,
    to_timestamp(observedTimeUnixNano) as observed_timestamp,
    spanId,
    traceId,
    a.value:value:stringValue as message,
    log_record
    FROM (SELECT
    value:timeUnixNano as timeUnixNano,
    value:observedTimeUnixNano as observedTimeUnixNano,
    value:spanId as spanId,
    value:traceId as traceId,
    value as log_record
    FROM TELEMETRY_SHARING.LOGS.TELEMETRY_LOAD_TABLE_&id, LATERAL FLATTEN( INPUT => TRY_PARSE_JSON($1):resourceLogs[0]:scopeLogs[0]:logRecords, OUTER => TRUE )),
    LATERAL FLATTEN( INPUT => log_record:body:kvlistValue:values, OUTER => TRUE) a, LATERAL FLATTEN( INPUT => log_record:attributes, OUTER => TRUE) b
    WHERE a.VALUE:key = 'message'
    and
    (
    ( -- engine unsafe logs
    b.value:key = 'log.file.name'
    and b.value:value:stringValue ='engine-unsafe.log'
    )
    or
    (
    -- erps unsafe logs
    log_record not like '%___safe_to_log%'
    and log_record not like '%engine-safe.log%'
    and log_record like '%spcs_control_plane%'
    )
    );
    END;
    """
    sql_query = (
    sql_query
    .replace('&warehouse', warehouse)
    .replace('&id', id)
    .replace('&event_sharing_account', event_sharing_account)
    .replace('&date_range', date_range)
    .replace('&native_app_name', native_app_name)
    .replace('&file_pattern', file_pattern)
    )
    # if running as a Snowflake notebook:
    session = get_active_session()
    # # if running as a local Jupyter notebook:
    # from snowflake.snowpark import Session
    #
    # connection_parameters = {
    # "account": "<your snowflake account>",
    # "user": "<your snowflake user>",
    # "password": "<your snowflake password>",
    # "role": "<your snowflake role>", # optional
    # "warehouse": "<your snowflake warehouse>", # optional
    # "database": "<your snowflake database>", # optional
    # "schema": "<your snowflake schema>", # optional
    # }
    #
    # session = Session.builder.configs(connection_parameters).create()
    session.sql(sql_query).collect()

    Run the following cell to confirm that the logs are copied to the secure share:

    session.sql("USE ROLE ACCOUNTADMIN").collect()
    session.sql(f"USE WAREHOUSE {warehouse}").collect()
    query = f"SELECT * FROM TELEMETRY_SHARING.LOGS.TELEMETRY_SHARE_TABLE_{id} LIMIT 5"
    session.sql(query).collect()
  2. Set the notebook inputs

    Before you update the configuration cell, gather the values that control which logs are copied and where the secure share is sent:

    InputWhat to decide
    start_date and end_dateThe date range to include in the log share.
    engine_nameA specific engine (i.e., reasoner) name, or .* if RelationalAI asked for logs across all engines.
    include_erps_logsWhether to include spcs_control_plane logs in addition to engine logs.
    warehouseThe Snowflake warehouse the notebook should use while building the share.
    idA unique identifier for this share so the created tables, view, and share do not collide with another run.
    event_sharing_accountThe target Snowflake account name that RelationalAI gives you for the secure share.
    native_app_nameThe installed app name, which is usually relationalai.

    Then update the configuration cell with the scope and sharing details you prepared:

    start_date = "YYYY-MM-DD"
    end_date = "YYYY-MM-DD"
    include_erps_logs = False
    engine_name = ".*"
    warehouse = "<warehouse_name>"
    id = "<unique_share_id>"
    event_sharing_account = "<org.account_name>"
    native_app_name = "relationalai"
  3. Run the notebook to create the secure share

    Run the notebook cells in order. The workflow computes the file pattern for your requested date range, creates the TELEMETRY_SHARING.LOGS objects, copies matching files from the app stage, filters the records, and grants the resulting secure share to the target account.

  4. Verify that the share contains the requested logs

    Run the verification cell at the end of the notebook, or run the equivalent query below:

    session.sql("USE ROLE ACCOUNTADMIN").collect()
    session.sql(f"USE WAREHOUSE {warehouse}").collect()
    query = f"SELECT * FROM TELEMETRY_SHARING.LOGS.TELEMETRY_SHARE_TABLE_{id} LIMIT 5"
    session.sql(query).collect()

    If the query returns rows, the filtered logs were copied into the share table and the secure share is populated.