77ready-to-use AuditClient.
88
99Usage:
10+ explicit config:
11+
1012 from sap_cloud_sdk.core.auditlog_ng import create_client, AuditLogNGConfig
1113
1214 config = AuditLogNGConfig(
1820 )
1921 client = create_client(config=config)
2022
23+ Usage:
24+ resolve from a Destination:
25+
26+ from sap_cloud_sdk.core.auditlog_ng import create_client
27+
28+ client = create_client(
29+ destination_name="my-audit-destination",
30+ destination_instance="my-binding-instance",
31+ fragment_name="prod-fragment", # optional
32+ )
33+
2134 # Send an audit event (protobuf message)
2235 event_id = client.send(event, "DataAccess")
2336 client.close()
2437"""
2538
2639from typing import Optional
40+ from enum import Enum
2741
2842from sap_cloud_sdk .core .auditlog_ng .client import AuditClient
2943from sap_cloud_sdk .core .auditlog_ng .config import (
4357)
4458
4559
60+ class _DestinationProperties (Enum ):
61+ DEPLOYMENT_ID = "deploymentId"
62+ DEPLOYMENT_REGION = "deploymentRegion"
63+ NAMESPACE = "namespace"
64+
65+
66+ def _get_config_from_destination (
67+ destination_name : Optional [str ],
68+ destination_instance : Optional [str ],
69+ fragment_name : Optional [str ] = None ,
70+ ) -> dict [str , str ]:
71+ """Resolve endpoint, deployment_id and namespace from a named Destination.
72+
73+ The destination must expose these custom properties:
74+
75+ - ``deploymentId`` (or ``deploymentRegion`` as fallback when absent/empty)
76+ - ``namespace``
77+
78+ The destination ``url`` is used as the OTLP endpoint.
79+ The lookup is always performed at ``ConsumptionLevel.SUBACCOUNT``.
80+
81+ Args:
82+ destination_name: Name of the destination to resolve.
83+ destination_instance: Destination service binding instance name,
84+ passed as ``instance=`` to ``destination.create_client()``.
85+ fragment_name: Optional fragment name merged into the destination
86+ before resolution. Wrapped in ``ConsumptionOptions`` when provided.
87+
88+ Returns:
89+ dict with keys ``endpoint``, ``deployment_id``, ``namespace``
90+ when destination is found.
91+
92+ Returns:
93+ None: If destination is not found.
94+
95+ Return:
96+ ValueError: If required properties are missing.
97+ """
98+ # Lazy import — keeps destination an optional dependency; importing auditlog_ng
99+ # in environments without the destination package continues to work.
100+ from sap_cloud_sdk .destination import (
101+ ConsumptionOptions ,
102+ ConsumptionLevel ,
103+ create_client as _dest_create_client ,
104+ )
105+
106+ dest_client = _dest_create_client (instance = destination_instance )
107+ options = (
108+ ConsumptionOptions (
109+ fragment_name = fragment_name , fragment_level = ConsumptionLevel .SUBACCOUNT
110+ )
111+ if fragment_name
112+ else None
113+ )
114+
115+ destination = dest_client .get_destination (
116+ name = destination_name , options = options , level = ConsumptionLevel .SUBACCOUNT
117+ )
118+
119+ if destination is None :
120+ return {}
121+
122+ endpoint = destination .url
123+ props = destination .properties
124+
125+ deployment_id = props .get (_DestinationProperties .DEPLOYMENT_ID .value ) or ""
126+ if not deployment_id :
127+ deployment_id = props .get (_DestinationProperties .DEPLOYMENT_REGION .value ) or ""
128+ if not deployment_id :
129+ raise ValueError (
130+ f"Destination '{ destination_name } ' must provide either the "
131+ f"'{ _DestinationProperties .DEPLOYMENT_ID .value } ' or "
132+ f"'{ _DestinationProperties .DEPLOYMENT_REGION .value } ' property"
133+ )
134+
135+ namespace = props .get (_DestinationProperties .NAMESPACE .value ) or ""
136+ if not namespace :
137+ raise ValueError (
138+ f"Destination '{ destination_name } ' must provide the "
139+ f"'{ _DestinationProperties .NAMESPACE .value } ' property"
140+ )
141+
142+ return {
143+ "endpoint" : endpoint ,
144+ "deployment_id" : deployment_id ,
145+ "namespace" : namespace ,
146+ }
147+
148+
46149def create_client (
47150 * ,
48151 config : Optional [AuditLogNGConfig ] = None ,
152+ # Destination-based resolution
153+ destination_name : Optional [str ] = "AuditLogV3_Destination" ,
154+ destination_instance : Optional [str ] = "default" ,
155+ fragment_name : Optional [str ] = None ,
156+ # Explicit connection parameters
49157 endpoint : Optional [str ] = None ,
50158 deployment_id : Optional [str ] = None ,
51159 namespace : Optional [str ] = None ,
@@ -61,13 +169,30 @@ def create_client(
61169) -> AuditClient :
62170 """Create an AuditClient for sending audit events over OTLP/gRPC.
63171
64- Either pass a pre-built ``config`` **or** the individual keyword arguments.
65- When ``config`` is provided the remaining keyword arguments are ignored.
172+ Three mutually exclusive ways to provide configuration (evaluated in order):
173+
174+ 1. **Explicit config object** — pass a pre-built :class:`AuditLogNGConfig`
175+ via ``config``; all other keyword arguments are ignored.
176+
177+ 2. **Destination-based resolution** — pass ``destination_name`` and
178+ ``destination_instance`` (both required); ``fragment_name`` is optional.
179+ The Destination module resolves the named destination at subaccount level
180+ and extracts ``endpoint``, ``deployment_id`` (with fallback to
181+ ``deploymentRegion``), and ``namespace`` from its properties.
182+
183+ 3. **Explicit keyword arguments** — pass ``endpoint``, ``deployment_id``,
184+ and ``namespace`` directly.
66185
67186 Args:
68187 _telemetry_source: Internal parameter for telemetry. Not for external use.
69188 config: Optional explicit configuration. If provided, all other
70- keyword arguments are ignored.
189+ keyword arguments are ignored.
190+ destination_name: Name of the SAP Destination to resolve. Must be
191+ combined with ``destination_instance`` to enter the destination path.
192+ destination_instance: Destination service binding instance name, passed
193+ as ``instance=`` to ``destination.create_client()``. Must be combined
194+ with ``destination_name`` to enter the destination path.
195+ fragment_name: Optional destination fragment name merged before resolution.
71196 endpoint: OTLP gRPC endpoint (``host:port``).
72197 deployment_id: Deployment identifier.
73198 namespace: Namespace identifier.
@@ -85,16 +210,28 @@ def create_client(
85210
86211 Raises:
87212 ClientCreationError: If client creation fails.
88- ValueError: If required parameters are missing.
213+ ValueError: If required parameters are missing or destination
214+ resolution fails.
89215 """
90216 try :
91217 if config is None :
92218 try :
93- if not endpoint or not deployment_id or not namespace :
94- raise ValueError (
95- "endpoint, deployment_id, and namespace are required "
96- "when config is not provided"
97- )
219+ resolved = _get_config_from_destination (
220+ destination_name = destination_name ,
221+ destination_instance = destination_instance ,
222+ fragment_name = fragment_name ,
223+ )
224+ if resolved :
225+ endpoint = resolved ["endpoint" ]
226+ deployment_id = resolved ["deployment_id" ]
227+ namespace = resolved ["namespace" ]
228+ else :
229+ if not endpoint or not deployment_id or not namespace :
230+ raise ValueError (
231+ "endpoint, deployment_id, and namespace are required "
232+ "when config or valid destination is not provided"
233+ )
234+
98235 config = AuditLogNGConfig (
99236 endpoint = endpoint ,
100237 deployment_id = deployment_id ,
0 commit comments