- {/* Logging Exporters (admin-owned OTEL trace destinations assigned to this identity) */}
+ {/* Logging Exporters: the union of destinations routing to this identity.
+ Own = destinations this identity listed in its metadata.logging_exporters.
+ Via scope = destinations whose credential_info.access targets this identity
+ (a team/org id, or global). Both directions count; we render them together,
+ marking how each entry was resolved. */}
-
-
- Logging Exporters
- {loggingExporters.length}
-
- {loggingExporters.length > 0 ? (
-
- {loggingExporters.map((name, index) => (
-
- {name}
-
- ))}
-
- ) : (
-
-
- No logging exporters assigned
-
- )}
+ {(() => {
+ const ownSet = new Set(loggingExporters);
+ const scopedOnly = scopedExporters.filter((name) => !ownSet.has(name));
+ const entries = [
+ ...loggingExporters.map((name) => ({ name, source: "own" as const })),
+ ...scopedOnly.map((name) => ({ name, source: "scope" as const })),
+ ];
+ return (
+ <>
+
+
+ Logging Exporters
+ {entries.length}
+
+ {entries.length > 0 ? (
+
+ {entries.map((entry, index) => (
+
+ {entry.name}
+ {entry.source === "scope" ? " (via scope)" : ""}
+
+ ))}
+
+ ) : (
+
+
+ No logging exporters assigned
+
+ )}
+ >
+ );
+ })()}
{/* Logging Integrations Section */}
diff --git a/ui/litellm-dashboard/src/components/organization/organization_view.tsx b/ui/litellm-dashboard/src/components/organization/organization_view.tsx
index 664f0bb5fa1..a02acbe07da 100644
--- a/ui/litellm-dashboard/src/components/organization/organization_view.tsx
+++ b/ui/litellm-dashboard/src/components/organization/organization_view.tsx
@@ -13,6 +13,7 @@ import MemberTable from "../common_components/MemberTable";
import UserSearchModal from "../common_components/user_search_modal";
import MCPServerSelector from "../mcp_server_management/MCPServerSelector";
import LoggingExportersSelect from "../logging_credentials/LoggingExportersSelect";
+import { useCredentials } from "@/app/(dashboard)/hooks/credentials/useCredentials";
import { ModelSelect } from "../ModelSelect/ModelSelect";
import NotificationsManager from "../molecules/notifications_manager";
import {
@@ -61,6 +62,25 @@ const OrganizationInfoView: React.FC
= ({
const teamAliasMap = useMemo(() => createTeamAliasMap(teams), [teams]);
+ // Destinations whose credential_info.access targets THIS org (or is global).
+ // Rendered alongside the org's own metadata.logging_exporters so the Logging
+ // Exporters card reflects BOTH routing directions, matching the resolver's
+ // union at request time.
+ const { data: orgCredentialsData } = useCredentials();
+ const scopedExportersForOrg = useMemo(() => {
+ const orgId = orgData?.organization_id;
+ if (orgId == null) return [];
+ return (orgCredentialsData?.credentials ?? [])
+ .filter((c) => c.credential_info?.credential_type === "logging")
+ .filter((c) => {
+ const access = c.credential_info?.access;
+ if (!access) return false;
+ if (access.global === true) return true;
+ return Array.isArray(access.orgs) && access.orgs.includes(orgId);
+ })
+ .map((c) => c.credential_name);
+ }, [orgCredentialsData?.credentials, orgData?.organization_id]);
+
const handleMemberAdd = async (values: any) => {
try {
if (accessToken == null) {
@@ -317,16 +337,27 @@ const OrganizationInfoView: React.FC = ({
Logging Exporters
- {Array.isArray(orgData.metadata?.logging_exporters) &&
- orgData.metadata.logging_exporters.length > 0 ? (
- orgData.metadata.logging_exporters.map((name: string, index: number) => (
-
- {name}
-
- ))
- ) : (
- None
- )}
+ {(() => {
+ const own = Array.isArray(orgData.metadata?.logging_exporters)
+ ? (orgData.metadata.logging_exporters as string[])
+ : [];
+ const ownSet = new Set(own);
+ const scopedOnly = scopedExportersForOrg.filter((n) => !ownSet.has(n));
+ const all = [
+ ...own.map((n) => ({ n, source: "own" as const })),
+ ...scopedOnly.map((n) => ({ n, source: "scope" as const })),
+ ];
+ return all.length > 0 ? (
+ all.map((e, i) => (
+
+ {e.n}
+ {e.source === "scope" ? " (via scope)" : ""}
+
+ ))
+ ) : (
+ None
+ );
+ })()}
@@ -523,18 +554,29 @@ const OrganizationInfoView: React.FC = ({
Logging Exporters
- {Array.isArray(orgData.metadata?.logging_exporters) &&
- orgData.metadata.logging_exporters.length > 0 ? (
-
- {orgData.metadata.logging_exporters.map((name: string, index: number) => (
-
- {name}
-
- ))}
-
- ) : (
-
None
- )}
+ {(() => {
+ const own = Array.isArray(orgData.metadata?.logging_exporters)
+ ? (orgData.metadata.logging_exporters as string[])
+ : [];
+ const ownSet = new Set(own);
+ const scopedOnly = scopedExportersForOrg.filter((n) => !ownSet.has(n));
+ const all = [
+ ...own.map((n) => ({ n, source: "own" as const })),
+ ...scopedOnly.map((n) => ({ n, source: "scope" as const })),
+ ];
+ return all.length > 0 ? (
+
+ {all.map((e, i) => (
+
+ {e.n}
+ {e.source === "scope" ? " (via scope)" : ""}
+
+ ))}
+
+ ) : (
+
None
+ );
+ })()}