You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polaris.apache.org by ad...@apache.org on 2026/07/30 08:00:50 UTC

(polaris) branch main updated: Introduce StructuredLogKeys constants for SLF4J addKeyValue calls (#5093)

This is an automated email from the ASF dual-hosted git repository.

adutra pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git


The following commit(s) were added to refs/heads/main by this push:
     new a94bff03c3 Introduce StructuredLogKeys constants for SLF4J addKeyValue calls (#5093)
a94bff03c3 is described below

commit a94bff03c3df6f092a0a71f080c337cc104f6a87
Author: Yuewei Zhou <91...@users.noreply.github.com>
AuthorDate: Thu Jul 30 01:00:45 2026 -0700

    Introduce StructuredLogKeys constants for SLF4J addKeyValue calls (#5093)
    
    Centralize hardcoded log key strings used in addKeyValue() calls into a
    single StructuredLogKeys constants class. This prevents typos, enables IDE
    autocomplete and find-all-references, and provides a single source of truth
    for structured log key names used in search and alerting.
    
    Replaces ~100 hardcoded string literals across 17 files with references to
    constants in StructuredLogKeys. The 4 remaining dynamic expression-based
    keys (e.g., 'entity.getTableIdentifier()') are left as-is since they
    represent variable names rather than stable log keys.
    
    Fixes #5033
    ---------
    
    Co-authored-by: Yuewei Zhou <yu...@amazon.com>
---
 .../org/apache/polaris/core/StructuredLogKeys.java | 106 +++++++++++++++++++++
 .../polaris/core/auth/PolarisAuthorizerImpl.java   |   3 +-
 .../core/persistence/PolarisObjectMapperUtil.java  |   5 +-
 .../azure/AzureCredentialsStorageIntegration.java  |  17 ++--
 .../gcp/GcpCredentialsStorageIntegration.java      |   9 +-
 .../polaris/service/admin/PolarisAdminService.java |   7 +-
 .../polaris/service/admin/PolarisServiceImpl.java  |   7 +-
 .../polaris/service/auth/DefaultAuthenticator.java |  15 +--
 .../generic/GenericTableCatalogHandler.java        |   3 +-
 .../catalog/iceberg/IcebergCatalogAdapter.java     |   5 +-
 .../catalog/iceberg/IcebergCatalogHandler.java     |  21 ++--
 .../catalog/iceberg/LocalIcebergCatalog.java       |   7 +-
 .../catalog/io/StorageAccessConfigProvider.java    |  11 ++-
 .../service/task/BatchFileCleanupTaskHandler.java  |  11 ++-
 .../service/task/FileCleanupTaskHandler.java       |  33 +++----
 .../task/ManifestFileCleanupTaskHandler.java       |   7 +-
 .../service/task/TableCleanupTaskHandler.java      |  46 ++++-----
 .../polaris/service/task/TaskExecutorImpl.java     |  14 +--
 18 files changed, 226 insertions(+), 101 deletions(-)

diff --git a/polaris-core/src/main/java/org/apache/polaris/core/StructuredLogKeys.java b/polaris-core/src/main/java/org/apache/polaris/core/StructuredLogKeys.java
new file mode 100644
index 0000000000..e4d1e5f6cd
--- /dev/null
+++ b/polaris-core/src/main/java/org/apache/polaris/core/StructuredLogKeys.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.core;
+
+/**
+ * Constants for structured log key names used in SLF4J {@code addKeyValue()} calls throughout the
+ * codebase. Centralizing these keys prevents typos, enables IDE autocomplete and
+ * find-all-references, and provides a single source of truth for log key names used in search and
+ * alerting.
+ */
+public final class StructuredLogKeys {
+  private StructuredLogKeys() {}
+
+  // --- Table-related keys ---
+  public static final String TABLE_IDENTIFIER = "tableIdentifier";
+  public static final String TABLE_ID = "tableId";
+  public static final String TABLE_NAME = "tableName";
+  public static final String TABLE_ENTITY = "tableEntity";
+  public static final String TABLE_LOCATION = "tableLocation";
+  public static final String TABLE_LOCATIONS = "tableLocations";
+
+  // --- View-related keys ---
+  public static final String VIEW_IDENTIFIER = "viewIdentifier";
+
+  // --- Namespace-related keys ---
+  public static final String NAMESPACE = "namespace";
+
+  // --- Catalog-related keys ---
+  public static final String CATALOG = "catalog";
+  public static final String CATALOG_NAME = "catalogName";
+
+  // --- Metadata keys ---
+  public static final String METADATA_LOCATION = "metadataLocation";
+  public static final String METADATA_FILES = "metadataFiles";
+
+  // --- File and storage keys ---
+  public static final String FILE = "file";
+  public static final String FILE_PATH = "filePath";
+  public static final String FILES = "files";
+  public static final String BASE_FILE = "baseFile";
+  public static final String BATCH_FILES = "batchFiles";
+  public static final String MANIFEST_FILE = "manifestFile";
+  public static final String MISSING_FILES = "missingFiles";
+  public static final String LOCATION = "location";
+  public static final String LOCATIONS = "locations";
+  public static final String READ_LOCATIONS = "readLocations";
+  public static final String WRITE_LOCATIONS = "writeLocations";
+  public static final String LIST_LOCATIONS = "listLocations";
+
+  // --- Credential and storage config keys ---
+  public static final String CREDENTIALS = "credentials";
+  public static final String CREDENTIAL_KEYS = "credentialKeys";
+  public static final String EXTRA_PROPERTIES = "extraProperties";
+  public static final String STORAGE_CONFIG = "storageConfig";
+  public static final String STORAGE_ACCOUNT = "storageAccount";
+  public static final String CONTAINER = "container";
+  public static final String ACCESS_BOUNDARY = "accessBoundary";
+  public static final String ALLOWED_LIST_ACTION = "allowedListAction";
+  public static final String ENDPOINT = "endpoint";
+  public static final String SECRET_REFERENCE = "secretReference";
+
+  // --- Principal and auth keys ---
+  public static final String PRINCIPAL = "principal";
+  public static final String PRINCIPAL_NAME = "principalName";
+  public static final String ROLE = "role";
+  public static final String ROLES = "roles";
+
+  // --- Task-related keys ---
+  public static final String TASK_ENTITY_ID = "taskEntityId";
+  public static final String TASK_ENTITY_NAME = "taskEntityName";
+  public static final String TASK_NAME = "taskName";
+  public static final String TASK_TYPE = "taskType";
+  public static final String TASK_COUNT = "taskCount";
+  public static final String HANDLER_CLASS = "handlerClass";
+  public static final String ATTEMPT = "attempt";
+  public static final String CONFIGURED_BATCH_SIZE = "configuredBatchSize";
+  public static final String EFFECTIVE_BATCH_SIZE = "effectiveBatchSize";
+
+  // --- Error keys ---
+  public static final String ERROR = "error";
+  public static final String ERR_MSG = "errMsg";
+  public static final String STACK_TRACE = "stackTrace";
+
+  // --- Misc keys ---
+  public static final String TYPE = "type";
+  public static final String IDENTIFIER = "identifier";
+  public static final String NOTIFICATION = "notification";
+  public static final String REMOTE_URL = "remoteUrl";
+  public static final String JSON = "json";
+}
diff --git a/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java
index fba64c8e51..a8fd1ce013 100644
--- a/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java
+++ b/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java
@@ -132,6 +132,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.iceberg.exceptions.ForbiddenException;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.auth.RbacOperationSemantics.ResolvedPathRooting;
 import org.apache.polaris.core.config.RealmConfig;
 import org.apache.polaris.core.entity.PolarisBaseEntity;
@@ -932,7 +933,7 @@ public class PolarisAuthorizerImpl implements PolarisAuthorizer {
       }
       LOGGER
           .atDebug()
-          .addKeyValue("principalName", polarisPrincipal.getName())
+          .addKeyValue(StructuredLogKeys.PRINCIPAL_NAME, polarisPrincipal.getName())
           .log("Root principal allowed to reset credentials");
     } else {
       List<MissingPrivilege> missing =
diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisObjectMapperUtil.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisObjectMapperUtil.java
index 9b1170aba6..03370921a9 100644
--- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisObjectMapperUtil.java
+++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisObjectMapperUtil.java
@@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper;
 import java.io.IOException;
 import java.util.Map;
 import org.apache.iceberg.rest.RESTSerializers;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.entity.PolarisBaseEntity;
 import org.apache.polaris.core.entity.PolarisTaskConstants;
 import org.jspecify.annotations.Nullable;
@@ -166,8 +167,8 @@ public final class PolarisObjectMapperUtil {
     } catch (IOException | NumberFormatException e) {
       LOGGER
           .atWarn()
-          .addKeyValue("json", entity.getProperties())
-          .addKeyValue("error", e.getMessage())
+          .addKeyValue(StructuredLogKeys.JSON, entity.getProperties())
+          .addKeyValue(StructuredLogKeys.ERROR, e.getMessage())
           .log("Unable to parse task properties");
       return null;
     }
diff --git a/polaris-core/src/main/java/org/apache/polaris/core/storage/azure/AzureCredentialsStorageIntegration.java b/polaris-core/src/main/java/org/apache/polaris/core/storage/azure/AzureCredentialsStorageIntegration.java
index 858b1164b5..007fd13a48 100644
--- a/polaris-core/src/main/java/org/apache/polaris/core/storage/azure/AzureCredentialsStorageIntegration.java
+++ b/polaris-core/src/main/java/org/apache/polaris/core/storage/azure/AzureCredentialsStorageIntegration.java
@@ -56,6 +56,7 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.config.RealmConfig;
 import org.apache.polaris.core.storage.CachingStorageIntegration;
 import org.apache.polaris.core.storage.CredentialVendingContext;
@@ -206,14 +207,14 @@ public class AzureCredentialsStorageIntegration
 
     LOGGER
         .atDebug()
-        .addKeyValue("allowedListAction", allowList)
-        .addKeyValue("locations", locations)
-        .addKeyValue("writeLocations", writeLocations)
-        .addKeyValue("location", loc)
-        .addKeyValue("storageAccount", location.getStorageAccount())
-        .addKeyValue("endpoint", location.getEndpoint())
-        .addKeyValue("container", location.getContainer())
-        .addKeyValue("filePath", filePath)
+        .addKeyValue(StructuredLogKeys.ALLOWED_LIST_ACTION, allowList)
+        .addKeyValue(StructuredLogKeys.LOCATIONS, locations)
+        .addKeyValue(StructuredLogKeys.WRITE_LOCATIONS, writeLocations)
+        .addKeyValue(StructuredLogKeys.LOCATION, loc)
+        .addKeyValue(StructuredLogKeys.STORAGE_ACCOUNT, location.getStorageAccount())
+        .addKeyValue(StructuredLogKeys.ENDPOINT, location.getEndpoint())
+        .addKeyValue(StructuredLogKeys.CONTAINER, location.getContainer())
+        .addKeyValue(StructuredLogKeys.FILE_PATH, filePath)
         .log("Subscope Azure SAS");
     String sasToken;
     if (location.getEndpoint().equalsIgnoreCase(AzureLocation.BLOB_ENDPOINT)) {
diff --git a/polaris-core/src/main/java/org/apache/polaris/core/storage/gcp/GcpCredentialsStorageIntegration.java b/polaris-core/src/main/java/org/apache/polaris/core/storage/gcp/GcpCredentialsStorageIntegration.java
index b4fcc5c799..f30c7eda63 100644
--- a/polaris-core/src/main/java/org/apache/polaris/core/storage/gcp/GcpCredentialsStorageIntegration.java
+++ b/polaris-core/src/main/java/org/apache/polaris/core/storage/gcp/GcpCredentialsStorageIntegration.java
@@ -45,6 +45,7 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.config.FeatureConfiguration;
 import org.apache.polaris.core.config.RealmConfig;
 import org.apache.polaris.core.storage.CachingStorageIntegration;
@@ -324,10 +325,10 @@ public class GcpCredentialsStorageIntegration
     } catch (IOException e) {
       LOGGER
           .atError()
-          .addKeyValue("readLocations", readLocations)
-          .addKeyValue("listLocations", listLocations)
-          .addKeyValue("writeLocations", writeLocations)
-          .addKeyValue("accessBoundary", convertToString(accessBoundary))
+          .addKeyValue(StructuredLogKeys.READ_LOCATIONS, readLocations)
+          .addKeyValue(StructuredLogKeys.LIST_LOCATIONS, listLocations)
+          .addKeyValue(StructuredLogKeys.WRITE_LOCATIONS, writeLocations)
+          .addKeyValue(StructuredLogKeys.ACCESS_BOUNDARY, convertToString(accessBoundary))
           .log("Unable to refresh access credentials", e);
       throw new RuntimeException("Unable to fetch access credentials " + e.getMessage());
     }
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java b/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java
index 938edbc69c..3506fd1771 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java
@@ -45,6 +45,7 @@ import org.apache.iceberg.exceptions.BadRequestException;
 import org.apache.iceberg.exceptions.NotFoundException;
 import org.apache.iceberg.exceptions.ValidationException;
 import org.apache.polaris.core.PolarisCallContext;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.admin.model.AuthenticationParameters;
 import org.apache.polaris.core.admin.model.BearerAuthenticationParameters;
 import org.apache.polaris.core.admin.model.Catalog;
@@ -286,7 +287,7 @@ public class PolarisAdminService {
     if (isSelfEntity(entity) && isSelfOperation(op)) {
       LOGGER
           .atDebug()
-          .addKeyValue("principalName", topLevelEntityName)
+          .addKeyValue(StructuredLogKeys.PRINCIPAL_NAME, topLevelEntityName)
           .log("Allowing rotate own credentials");
     } else {
       authorizer.authorizeOrThrow(
@@ -800,7 +801,7 @@ public class PolarisAdminService {
                 LOGGER
                     .atWarn()
                     .setCause(e)
-                    .addKeyValue("secretReference", secretReference.urn())
+                    .addKeyValue(StructuredLogKeys.SECRET_REFERENCE, secretReference.urn())
                     .log(
                         "Failed to clean up secret {} after catalog creation failure",
                         secretReference.urn());
@@ -848,7 +849,7 @@ public class PolarisAdminService {
         if (connectionConfigInfo != null) {
           LOGGER
               .atDebug()
-              .addKeyValue("catalogName", entity.getName())
+              .addKeyValue(StructuredLogKeys.CATALOG_NAME, entity.getName())
               .log("Creating a federated catalog");
           FeatureConfiguration.enforceFeatureEnabledOrThrow(
               realmConfig, FeatureConfiguration.ENABLE_CATALOG_FEDERATION);
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisServiceImpl.java b/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisServiceImpl.java
index 1d738180fe..fe648588b0 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisServiceImpl.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisServiceImpl.java
@@ -29,6 +29,7 @@ import java.util.Map;
 import org.apache.iceberg.catalog.Namespace;
 import org.apache.iceberg.catalog.TableIdentifier;
 import org.apache.iceberg.rest.responses.ErrorResponse;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.admin.model.AddGrantRequest;
 import org.apache.polaris.core.admin.model.AuthenticationParameters;
 import org.apache.polaris.core.admin.model.AwsStorageConfigInfo;
@@ -142,7 +143,7 @@ public class PolarisServiceImpl
     if (!allowedStorageTypes.contains(storageConfigInfo.getStorageType().name())) {
       LOGGER
           .atWarn()
-          .addKeyValue("storageConfig", storageConfigInfo)
+          .addKeyValue(StructuredLogKeys.STORAGE_CONFIG, storageConfigInfo)
           .log("Disallowed storage type in catalog");
       throw new IllegalArgumentException(
           "Unsupported storage type: " + storageConfigInfo.getStorageType());
@@ -693,8 +694,8 @@ public class PolarisServiceImpl
       default:
         LOGGER
             .atWarn()
-            .addKeyValue("catalog", catalogName)
-            .addKeyValue("role", catalogRoleName)
+            .addKeyValue(StructuredLogKeys.CATALOG, catalogName)
+            .addKeyValue(StructuredLogKeys.ROLE, catalogRoleName)
             .log(
                 "Don't know how to handle privilege {}: {}",
                 direction == GrantDirection.GRANT ? "grant" : "revocation",
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/auth/DefaultAuthenticator.java b/runtime/service/src/main/java/org/apache/polaris/service/auth/DefaultAuthenticator.java
index fd6ab7c7a1..baa38ede55 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/auth/DefaultAuthenticator.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/auth/DefaultAuthenticator.java
@@ -32,6 +32,7 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.polaris.core.PolarisCallContext;
 import org.apache.polaris.core.PolarisDiagnostics;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.auth.PolarisPrincipal;
 import org.apache.polaris.core.context.CallContext;
 import org.apache.polaris.core.entity.PolarisBaseEntity;
@@ -145,8 +146,8 @@ public class DefaultAuthenticator implements Authenticator {
     } catch (Exception e) {
       LOGGER
           .atError()
-          .addKeyValue("errMsg", e.getMessage())
-          .addKeyValue("stackTrace", Throwables.getStackTraceAsString(e))
+          .addKeyValue(StructuredLogKeys.ERR_MSG, e.getMessage())
+          .addKeyValue(StructuredLogKeys.STACK_TRACE, Throwables.getStackTraceAsString(e))
           .log("Unable to resolve principal entity from credentials");
       throw new ServiceUnavailableException("Unable to fetch principal entity");
     }
@@ -206,9 +207,9 @@ public class DefaultAuthenticator implements Authenticator {
     if (!requestedRoles.allRolesRequested() && !activeRoles.containsAll(requestedRoles.roles())) {
       LOGGER
           .atWarn()
-          .addKeyValue("principal", principal.getName())
-          .addKeyValue("credentials", credentials)
-          .addKeyValue("roles", activeRoles)
+          .addKeyValue(StructuredLogKeys.PRINCIPAL, principal.getName())
+          .addKeyValue(StructuredLogKeys.CREDENTIALS, credentials)
+          .addKeyValue(StructuredLogKeys.ROLES, activeRoles)
           .log("Some principal roles were not found in the principal's grants");
       throw new AuthenticationFailedException("Unable to authenticate");
     }
@@ -233,8 +234,8 @@ public class DefaultAuthenticator implements Authenticator {
     if (credentialsRoles.stream().anyMatch(s -> !s.startsWith(PRINCIPAL_ROLE_PREFIX))) {
       LOGGER
           .atWarn()
-          .addKeyValue("credentials", credentials)
-          .addKeyValue("roles", credentialsRoles)
+          .addKeyValue(StructuredLogKeys.CREDENTIALS, credentials)
+          .addKeyValue(StructuredLogKeys.ROLES, credentialsRoles)
           .log(
               "Credentials contain roles that do not start with expected prefix '{}'. "
                   + "These roles will be ignored during authentication.",
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
index 3546385ddd..51d6bcd3b4 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/GenericTableCatalogHandler.java
@@ -24,6 +24,7 @@ import java.util.LinkedHashSet;
 import java.util.Map;
 import org.apache.iceberg.catalog.Namespace;
 import org.apache.iceberg.catalog.TableIdentifier;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.auth.PolarisAuthorizableOperation;
 import org.apache.polaris.core.catalog.FederatedCatalogFactory;
 import org.apache.polaris.core.catalog.GenericTableCatalog;
@@ -61,7 +62,7 @@ public abstract class GenericTableCatalogHandler extends CatalogHandler {
     if (connectionConfigInfoDpo != null) {
       LOGGER
           .atInfo()
-          .addKeyValue("remoteUrl", connectionConfigInfoDpo.getUri())
+          .addKeyValue(StructuredLogKeys.REMOTE_URL, connectionConfigInfoDpo.getUri())
           .log("Initializing federated catalog");
       FeatureConfiguration.enforceFeatureEnabledOrThrow(
           realmConfig(), FeatureConfiguration.ENABLE_CATALOG_FEDERATION);
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
index 427e3d093f..0f68060686 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogAdapter.java
@@ -46,6 +46,7 @@ import org.apache.iceberg.rest.requests.ReportMetricsRequest;
 import org.apache.iceberg.rest.requests.UpdateNamespacePropertiesRequest;
 import org.apache.iceberg.rest.requests.UpdateTableRequest;
 import org.apache.iceberg.rest.responses.LoadTableResponse;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.auth.PolarisPrincipal;
 import org.apache.polaris.core.config.RealmConfig;
 import org.apache.polaris.core.context.CallContext;
@@ -197,8 +198,8 @@ public class IcebergCatalogAdapter
     } else {
       LOGGER
           .atWarn()
-          .addKeyValue("namespace", namespace)
-          .addKeyValue("tableName", tableName)
+          .addKeyValue(StructuredLogKeys.NAMESPACE, namespace)
+          .addKeyValue(StructuredLogKeys.TABLE_NAME, tableName)
           .log("Response has null metadataLocation; omitting etag");
     }
     return builder;
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
index a4a3402751..d5777f73a1 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
@@ -88,6 +88,7 @@ import org.apache.iceberg.rest.responses.LoadTableResponse;
 import org.apache.iceberg.rest.responses.LoadViewResponse;
 import org.apache.iceberg.rest.responses.UpdateNamespacePropertiesResponse;
 import org.apache.polaris.core.PolarisDiagnostics;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.auth.AuthorizationRequest;
 import org.apache.polaris.core.auth.AuthorizationState;
 import org.apache.polaris.core.auth.PolarisAuthorizableOperation;
@@ -225,7 +226,7 @@ public abstract class IcebergCatalogHandler extends CatalogHandler implements Au
     if (connectionConfigInfoDpo != null) {
       LOGGER
           .atInfo()
-          .addKeyValue("remoteUrl", connectionConfigInfoDpo.getUri())
+          .addKeyValue(StructuredLogKeys.REMOTE_URL, connectionConfigInfoDpo.getUri())
           .log("Initializing federated catalog");
       FeatureConfiguration.enforceFeatureEnabledOrThrow(
           realmConfig(), FeatureConfiguration.ENABLE_CATALOG_FEDERATION);
@@ -801,8 +802,8 @@ public abstract class IcebergCatalogHandler extends CatalogHandler implements Au
         .equals(org.apache.polaris.core.admin.model.Catalog.TypeEnum.INTERNAL)) {
       LOGGER
           .atWarn()
-          .addKeyValue("catalog", catalog)
-          .addKeyValue("notification", request)
+          .addKeyValue(StructuredLogKeys.CATALOG, catalog)
+          .addKeyValue(StructuredLogKeys.NOTIFICATION, request)
           .log("Attempted notification on internal catalog");
       throw new BadRequestException("Cannot update internal catalog via notifications");
     }
@@ -972,7 +973,7 @@ public abstract class IcebergCatalogHandler extends CatalogHandler implements Au
     if (baseLocation == null) {
       LOGGER
           .atDebug()
-          .addKeyValue("tableIdentifier", tableIdentifier)
+          .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableIdentifier)
           .log(
               "Entity missing location in internal properties, requires backfill "
                   + "as it was likely not updated with stored property changes. "
@@ -1154,8 +1155,8 @@ public abstract class IcebergCatalogHandler extends CatalogHandler implements Au
       if (tableEntity == null || tableEntity.getMetadataLocation() == null) {
         LOGGER
             .atWarn()
-            .addKeyValue("tableIdentifier", tableIdentifier)
-            .addKeyValue("tableEntity", tableEntity)
+            .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableIdentifier)
+            .addKeyValue(StructuredLogKeys.TABLE_ENTITY, tableEntity)
             .log("Failed to getMetadataLocation to generate ETag when loading table");
       } else {
         // TODO: Refactor null-checking into the helper method once we create a more canonical
@@ -1266,14 +1267,14 @@ public abstract class IcebergCatalogHandler extends CatalogHandler implements Au
 
       LOGGER
           .atInfo()
-          .addKeyValue("tableIdentifier", tableIdentifier)
-          .addKeyValue("tableLocations", tableLocations)
+          .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableIdentifier)
+          .addKeyValue(StructuredLogKeys.TABLE_LOCATIONS, tableLocations)
           .log("Validated table locations for credential vending");
     } catch (ForbiddenException e) {
       LOGGER
           .atError()
-          .addKeyValue("tableIdentifier", tableIdentifier)
-          .addKeyValue("tableLocations", tableLocations)
+          .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableIdentifier)
+          .addKeyValue(StructuredLogKeys.TABLE_LOCATIONS, tableLocations)
           .log("Table locations validation failed for credential vending");
       throw new ForbiddenException(
           "Table '%s' has locations outside the catalog's current allowed locations: %s",
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/LocalIcebergCatalog.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/LocalIcebergCatalog.java
index f7545bfc50..64fc73dddd 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/LocalIcebergCatalog.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/LocalIcebergCatalog.java
@@ -99,6 +99,7 @@ import org.apache.iceberg.view.ViewProperties;
 import org.apache.iceberg.view.ViewUtil;
 import org.apache.polaris.core.PolarisCallContext;
 import org.apache.polaris.core.PolarisDiagnostics;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.auth.PolarisPrincipal;
 import org.apache.polaris.core.catalog.PolarisCatalogHelpers;
 import org.apache.polaris.core.config.BehaviorChangeConfiguration;
@@ -1803,7 +1804,7 @@ public class LocalIcebergCatalog extends BaseMetastoreViewCatalog
           LOGGER
               .atError()
               .addKeyValue("entity.getTableIdentifier()", entity.getTableIdentifier())
-              .addKeyValue("tableIdentifier", tableIdentifier)
+              .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableIdentifier)
               .log("Stored table identifier mismatches requested identifier");
         }
       }
@@ -2290,7 +2291,7 @@ public class LocalIcebergCatalog extends BaseMetastoreViewCatalog
           LOGGER
               .atError()
               .addKeyValue("entity.getTableIdentifier()", entity.getTableIdentifier())
-              .addKeyValue("identifier", identifier)
+              .addKeyValue(StructuredLogKeys.IDENTIFIER, identifier)
               .log("Stored view identifier mismatches requested identifier");
         }
       }
@@ -3136,7 +3137,7 @@ public class LocalIcebergCatalog extends BaseMetastoreViewCatalog
           LOGGER
               .atInfo()
               .setCause(aee)
-              .addKeyValue("namespace", namespace)
+              .addKeyValue(StructuredLogKeys.NAMESPACE, namespace)
               .log("Namespace already exists in createNonExistingNamespace");
         }
       }
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/io/StorageAccessConfigProvider.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/io/StorageAccessConfigProvider.java
index 11d63ff990..6b57b04248 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/io/StorageAccessConfigProvider.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/io/StorageAccessConfigProvider.java
@@ -28,6 +28,7 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.iceberg.catalog.TableIdentifier;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.auth.PolarisPrincipal;
 import org.apache.polaris.core.config.FeatureConfiguration;
 import org.apache.polaris.core.context.CallContext;
@@ -80,8 +81,8 @@ public class StorageAccessConfigProvider {
       @NonNull PolarisResolvedPathWrapper resolvedPath) {
     LOGGER
         .atDebug()
-        .addKeyValue("tableIdentifier", tableIdentifier)
-        .addKeyValue("tableLocation", tableLocations)
+        .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableIdentifier)
+        .addKeyValue(StructuredLogKeys.TABLE_LOCATION, tableLocations)
         .log("Fetching client credentials for table");
 
     StorageAccessConfig accessConfig =
@@ -93,9 +94,9 @@ public class StorageAccessConfigProvider {
 
     LOGGER
         .atDebug()
-        .addKeyValue("tableIdentifier", tableIdentifier)
-        .addKeyValue("credentialKeys", accessConfig.credentials().keySet())
-        .addKeyValue("extraProperties", accessConfig.extraProperties())
+        .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableIdentifier)
+        .addKeyValue(StructuredLogKeys.CREDENTIAL_KEYS, accessConfig.credentials().keySet())
+        .addKeyValue(StructuredLogKeys.EXTRA_PROPERTIES, accessConfig.extraProperties())
         .log("Loaded scoped credentials for table");
     if (accessConfig.credentials().isEmpty()) {
       LOGGER.debug("No credentials found for table");
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/task/BatchFileCleanupTaskHandler.java b/runtime/service/src/main/java/org/apache/polaris/service/task/BatchFileCleanupTaskHandler.java
index 02f5bdeffa..8b4f0ecc84 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/task/BatchFileCleanupTaskHandler.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/task/BatchFileCleanupTaskHandler.java
@@ -25,6 +25,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.stream.Collectors;
 import org.apache.iceberg.catalog.TableIdentifier;
 import org.apache.iceberg.io.FileIO;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.context.CallContext;
 import org.apache.polaris.core.entity.AsyncTaskType;
 import org.apache.polaris.core.entity.TaskEntity;
@@ -64,17 +65,17 @@ public class BatchFileCleanupTaskHandler extends FileCleanupTaskHandler {
       if (validFiles.isEmpty()) {
         LOGGER
             .atWarn()
-            .addKeyValue("batchFiles", batchFiles.toString())
-            .addKeyValue("tableId", tableId)
+            .addKeyValue(StructuredLogKeys.BATCH_FILES, batchFiles.toString())
+            .addKeyValue(StructuredLogKeys.TABLE_ID, tableId)
             .log("File batch cleanup task scheduled, but none of the files in batch exists");
         return;
       }
       if (!missingFiles.isEmpty()) {
         LOGGER
             .atWarn()
-            .addKeyValue("batchFiles", batchFiles.toString())
-            .addKeyValue("missingFiles", missingFiles.toString())
-            .addKeyValue("tableId", tableId)
+            .addKeyValue(StructuredLogKeys.BATCH_FILES, batchFiles.toString())
+            .addKeyValue(StructuredLogKeys.MISSING_FILES, missingFiles.toString())
+            .addKeyValue(StructuredLogKeys.TABLE_ID, tableId)
             .log(
                 "File batch cleanup task scheduled, but {} files in the batch are missing",
                 missingFiles.size());
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/task/FileCleanupTaskHandler.java b/runtime/service/src/main/java/org/apache/polaris/service/task/FileCleanupTaskHandler.java
index 2922bc3db5..86c9c84519 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/task/FileCleanupTaskHandler.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/task/FileCleanupTaskHandler.java
@@ -25,6 +25,7 @@ import org.apache.iceberg.CatalogUtil;
 import org.apache.iceberg.catalog.TableIdentifier;
 import org.apache.iceberg.exceptions.NotFoundException;
 import org.apache.iceberg.io.FileIO;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.context.CallContext;
 import org.apache.polaris.core.entity.TaskEntity;
 import org.slf4j.Logger;
@@ -85,9 +86,9 @@ public abstract class FileCleanupTaskHandler implements TaskHandler {
     if (e != null && attempt <= MAX_ATTEMPTS) {
       LOGGER
           .atWarn()
-          .addKeyValue("file", file)
-          .addKeyValue("attempt", attempt)
-          .addKeyValue("error", e.getMessage())
+          .addKeyValue(StructuredLogKeys.FILE, file)
+          .addKeyValue(StructuredLogKeys.ATTEMPT, attempt)
+          .addKeyValue(StructuredLogKeys.ERROR, e.getMessage())
           .log("Error encountered attempting to delete file");
     }
     if (attempt > MAX_ATTEMPTS && e != null) {
@@ -106,9 +107,9 @@ public abstract class FileCleanupTaskHandler implements TaskHandler {
                 // already gone (e.g. InMemoryFileIO or race)
                 LOGGER
                     .atDebug()
-                    .addKeyValue("file", file)
-                    .addKeyValue("baseFile", baseFile != null ? baseFile : "")
-                    .addKeyValue("tableId", tableId)
+                    .addKeyValue(StructuredLogKeys.FILE, file)
+                    .addKeyValue(StructuredLogKeys.BASE_FILE, baseFile != null ? baseFile : "")
+                    .addKeyValue(StructuredLogKeys.TABLE_ID, tableId)
                     .log("table file cleanup task scheduled, but data file doesn't exist");
               }
             },
@@ -117,9 +118,9 @@ public abstract class FileCleanupTaskHandler implements TaskHandler {
             newEx -> {
               LOGGER
                   .atWarn()
-                  .addKeyValue("file", file)
-                  .addKeyValue("tableIdentifier", tableId)
-                  .addKeyValue("baseFile", baseFile != null ? baseFile : "")
+                  .addKeyValue(StructuredLogKeys.FILE, file)
+                  .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableId)
+                  .addKeyValue(StructuredLogKeys.BASE_FILE, baseFile != null ? baseFile : "")
                   .log("Exception caught deleting data file {}", newEx);
               return tryDelete(tableId, fileIO, baseFile, file, newEx, attempt + 1);
             },
@@ -151,10 +152,10 @@ public abstract class FileCleanupTaskHandler implements TaskHandler {
     if (e != null && attempt <= MAX_ATTEMPTS) {
       LOGGER
           .atWarn()
-          .addKeyValue("files", files)
-          .addKeyValue("attempt", attempt)
-          .addKeyValue("error", e.getMessage())
-          .addKeyValue("type", type)
+          .addKeyValue(StructuredLogKeys.FILES, files)
+          .addKeyValue(StructuredLogKeys.ATTEMPT, attempt)
+          .addKeyValue(StructuredLogKeys.ERROR, e.getMessage())
+          .addKeyValue(StructuredLogKeys.TYPE, type)
           .log("Error encountered attempting to delete files");
     }
     if (attempt > MAX_ATTEMPTS && e != null) {
@@ -166,9 +167,9 @@ public abstract class FileCleanupTaskHandler implements TaskHandler {
             newEx -> {
               LOGGER
                   .atWarn()
-                  .addKeyValue("files", files)
-                  .addKeyValue("tableIdentifier", tableId)
-                  .addKeyValue("type", type)
+                  .addKeyValue(StructuredLogKeys.FILES, files)
+                  .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableId)
+                  .addKeyValue(StructuredLogKeys.TYPE, type)
                   .log("Exception caught deleting data files {}", newEx);
               return tryDelete(tableId, fileIO, files, type, isConcurrent, newEx, attempt + 1);
             },
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/task/ManifestFileCleanupTaskHandler.java b/runtime/service/src/main/java/org/apache/polaris/service/task/ManifestFileCleanupTaskHandler.java
index 7c17e61fb6..c3b4c78b5b 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/task/ManifestFileCleanupTaskHandler.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/task/ManifestFileCleanupTaskHandler.java
@@ -33,6 +33,7 @@ import org.apache.iceberg.ManifestFiles;
 import org.apache.iceberg.ManifestReader;
 import org.apache.iceberg.catalog.TableIdentifier;
 import org.apache.iceberg.io.FileIO;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.context.CallContext;
 import org.apache.polaris.core.entity.AsyncTaskType;
 import org.apache.polaris.core.entity.TaskEntity;
@@ -76,8 +77,8 @@ public class ManifestFileCleanupTaskHandler extends FileCleanupTaskHandler {
     if (!TaskUtils.exists(manifestFile.path(), fileIO)) {
       LOGGER
           .atWarn()
-          .addKeyValue("manifestFile", manifestFile.path())
-          .addKeyValue("tableId", tableId)
+          .addKeyValue(StructuredLogKeys.MANIFEST_FILE, manifestFile.path())
+          .addKeyValue(StructuredLogKeys.TABLE_ID, tableId)
           .log("Manifest cleanup task scheduled, but manifest file doesn't exist");
       return;
     }
@@ -103,7 +104,7 @@ public class ManifestFileCleanupTaskHandler extends FileCleanupTaskHandler {
                 (v) -> {
                   LOGGER
                       .atInfo()
-                      .addKeyValue("manifestFile", manifestFile.path())
+                      .addKeyValue(StructuredLogKeys.MANIFEST_FILE, manifestFile.path())
                       .log("All content files in manifest deleted - deleting manifest");
                   return tryDelete(
                       tableId, fileIO, manifestFile.path(), manifestFile.path(), null, 1);
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/task/TableCleanupTaskHandler.java b/runtime/service/src/main/java/org/apache/polaris/service/task/TableCleanupTaskHandler.java
index 218ca7af12..8cb9be2a47 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/task/TableCleanupTaskHandler.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/task/TableCleanupTaskHandler.java
@@ -36,6 +36,7 @@ import org.apache.iceberg.TableMetadata;
 import org.apache.iceberg.TableMetadataParser;
 import org.apache.iceberg.io.FileIO;
 import org.apache.polaris.core.PolarisCallContext;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.context.CallContext;
 import org.apache.polaris.core.entity.AsyncTaskType;
 import org.apache.polaris.core.entity.PolarisBaseEntity;
@@ -98,8 +99,8 @@ public class TableCleanupTaskHandler implements TaskHandler {
       TaskEntity cleanupTask, IcebergTableLikeEntity tableEntity, CallContext callContext) {
     LOGGER
         .atInfo()
-        .addKeyValue("tableIdentifier", tableEntity.getTableIdentifier())
-        .addKeyValue("metadataLocation", tableEntity.getMetadataLocation())
+        .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableEntity.getTableIdentifier())
+        .addKeyValue(StructuredLogKeys.METADATA_LOCATION, tableEntity.getMetadataLocation())
         .log("Handling table metadata cleanup task");
 
     // It's likely the cleanupTask has already been completed, but wasn't dropped successfully.
@@ -109,8 +110,8 @@ public class TableCleanupTaskHandler implements TaskHandler {
       if (!TaskUtils.exists(tableEntity.getMetadataLocation(), fileIO)) {
         LOGGER
             .atWarn()
-            .addKeyValue("tableIdentifier", tableEntity.getTableIdentifier())
-            .addKeyValue("metadataLocation", tableEntity.getMetadataLocation())
+            .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableEntity.getTableIdentifier())
+            .addKeyValue(StructuredLogKeys.METADATA_LOCATION, tableEntity.getMetadataLocation())
             .log("Table metadata cleanup scheduled, but metadata file does not exist");
         return;
       }
@@ -145,9 +146,9 @@ public class TableCleanupTaskHandler implements TaskHandler {
       if (createdTasks != null) {
         LOGGER
             .atInfo()
-            .addKeyValue("tableIdentifier", tableEntity.getTableIdentifier())
-            .addKeyValue("metadataLocation", tableEntity.getMetadataLocation())
-            .addKeyValue("taskCount", taskEntities.size())
+            .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableEntity.getTableIdentifier())
+            .addKeyValue(StructuredLogKeys.METADATA_LOCATION, tableEntity.getMetadataLocation())
+            .addKeyValue(StructuredLogKeys.TASK_COUNT, taskEntities.size())
             .log(
                 "Successfully queued tasks to delete manifests, previous metadata, and statistics files - deleting table metadata file");
         for (PolarisBaseEntity createdTask : createdTasks) {
@@ -166,16 +167,16 @@ public class TableCleanupTaskHandler implements TaskHandler {
   private void handleViewCleanup(TaskEntity cleanupTask, IcebergTableLikeEntity viewEntity) {
     LOGGER
         .atInfo()
-        .addKeyValue("viewIdentifier", viewEntity.getTableIdentifier())
-        .addKeyValue("metadataLocation", viewEntity.getMetadataLocation())
+        .addKeyValue(StructuredLogKeys.VIEW_IDENTIFIER, viewEntity.getTableIdentifier())
+        .addKeyValue(StructuredLogKeys.METADATA_LOCATION, viewEntity.getMetadataLocation())
         .log("Handling view metadata cleanup task");
 
     try (FileIO fileIO = fileIOSupplier.apply(cleanupTask, viewEntity.getTableIdentifier())) {
       if (!TaskUtils.exists(viewEntity.getMetadataLocation(), fileIO)) {
         LOGGER
             .atWarn()
-            .addKeyValue("viewIdentifier", viewEntity.getTableIdentifier())
-            .addKeyValue("metadataLocation", viewEntity.getMetadataLocation())
+            .addKeyValue(StructuredLogKeys.VIEW_IDENTIFIER, viewEntity.getTableIdentifier())
+            .addKeyValue(StructuredLogKeys.METADATA_LOCATION, viewEntity.getMetadataLocation())
             .log("View metadata cleanup scheduled, but metadata file does not exist");
         return;
       }
@@ -183,8 +184,8 @@ public class TableCleanupTaskHandler implements TaskHandler {
       fileIO.deleteFile(viewEntity.getMetadataLocation());
       LOGGER
           .atInfo()
-          .addKeyValue("viewIdentifier", viewEntity.getTableIdentifier())
-          .addKeyValue("metadataLocation", viewEntity.getMetadataLocation())
+          .addKeyValue(StructuredLogKeys.VIEW_IDENTIFIER, viewEntity.getTableIdentifier())
+          .addKeyValue(StructuredLogKeys.METADATA_LOCATION, viewEntity.getMetadataLocation())
           .log("Successfully deleted view metadata file");
 
       return;
@@ -222,10 +223,11 @@ public class TableCleanupTaskHandler implements TaskHandler {
               String taskName = cleanupTask.getName() + "_" + mf.path() + "_" + UUID.randomUUID();
               LOGGER
                   .atDebug()
-                  .addKeyValue("taskName", taskName)
-                  .addKeyValue("tableIdentifier", tableEntity.getTableIdentifier())
-                  .addKeyValue("metadataLocation", tableEntity.getMetadataLocation())
-                  .addKeyValue("manifestFile", mf.path())
+                  .addKeyValue(StructuredLogKeys.TASK_NAME, taskName)
+                  .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableEntity.getTableIdentifier())
+                  .addKeyValue(
+                      StructuredLogKeys.METADATA_LOCATION, tableEntity.getMetadataLocation())
+                  .addKeyValue(StructuredLogKeys.MANIFEST_FILE, mf.path())
                   .log("Queueing task to delete manifest file");
               return new TaskEntity.Builder()
                   .setName(taskName)
@@ -254,8 +256,8 @@ public class TableCleanupTaskHandler implements TaskHandler {
     if (batchSize != configuredBatchSize) {
       LOGGER
           .atWarn()
-          .addKeyValue("configuredBatchSize", configuredBatchSize)
-          .addKeyValue("effectiveBatchSize", batchSize)
+          .addKeyValue(StructuredLogKeys.CONFIGURED_BATCH_SIZE, configuredBatchSize)
+          .addKeyValue(StructuredLogKeys.EFFECTIVE_BATCH_SIZE, batchSize)
           .log("Invalid TABLE_METADATA_CLEANUP_BATCH_SIZE; clamping to minimum value");
     }
     return getMetadataFileBatches(tableMetadata, batchSize).stream()
@@ -269,9 +271,9 @@ public class TableCleanupTaskHandler implements TaskHandler {
                       UUID.randomUUID().toString());
               LOGGER
                   .atDebug()
-                  .addKeyValue("taskName", taskName)
-                  .addKeyValue("tableIdentifier", tableEntity.getTableIdentifier())
-                  .addKeyValue("metadataFiles", metadataBatch.toString())
+                  .addKeyValue(StructuredLogKeys.TASK_NAME, taskName)
+                  .addKeyValue(StructuredLogKeys.TABLE_IDENTIFIER, tableEntity.getTableIdentifier())
+                  .addKeyValue(StructuredLogKeys.METADATA_FILES, metadataBatch.toString())
                   .log(
                       "Queueing task to delete metadata files (prev metadata and statistics files)");
               return new TaskEntity.Builder()
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/task/TaskExecutorImpl.java b/runtime/service/src/main/java/org/apache/polaris/service/task/TaskExecutorImpl.java
index e930502627..dc4572b299 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/task/TaskExecutorImpl.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/task/TaskExecutorImpl.java
@@ -38,6 +38,7 @@ import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import org.apache.commons.lang3.function.TriConsumer;
+import org.apache.polaris.core.StructuredLogKeys;
 import org.apache.polaris.core.auth.ImmutablePolarisPrincipal;
 import org.apache.polaris.core.auth.PolarisPrincipal;
 import org.apache.polaris.core.context.CallContext;
@@ -227,8 +228,8 @@ public class TaskExecutorImpl implements TaskExecutor {
       if (handlerOpt.isEmpty()) {
         LOGGER
             .atWarn()
-            .addKeyValue("taskEntityId", taskEntityId)
-            .addKeyValue("taskType", task.getTaskType())
+            .addKeyValue(StructuredLogKeys.TASK_ENTITY_ID, taskEntityId)
+            .addKeyValue(StructuredLogKeys.TASK_TYPE, task.getTaskType())
             .log("Unable to find handler for task type");
         throw new TaskHandlerNotFoundException(
             "Unable to find handler for task type "
@@ -244,8 +245,8 @@ public class TaskExecutorImpl implements TaskExecutor {
       success = true;
       LOGGER
           .atInfo()
-          .addKeyValue("taskEntityId", taskEntityId)
-          .addKeyValue("handlerClass", handler.getClass())
+          .addKeyValue(StructuredLogKeys.TASK_ENTITY_ID, taskEntityId)
+          .addKeyValue(StructuredLogKeys.HANDLER_CLASS, handler.getClass())
           .log("Task successfully handled");
       metaStoreManager.dropEntityIfExists(
           ctx.getPolarisCallContext(), null, taskEntity, Map.of(), false);
@@ -258,8 +259,9 @@ public class TaskExecutorImpl implements TaskExecutor {
       if (!success) {
         LOGGER
             .atWarn()
-            .addKeyValue("taskEntityId", taskEntityId)
-            .addKeyValue("taskEntityName", taskEntity != null ? taskEntity.getName() : "")
+            .addKeyValue(StructuredLogKeys.TASK_ENTITY_ID, taskEntityId)
+            .addKeyValue(
+                StructuredLogKeys.TASK_ENTITY_NAME, taskEntity != null ? taskEntity.getName() : "")
             .log("Unable to execute async task");
       }
       throw e;