#!/usr/bin/env python# -*- coding: utf-8 -*--# Copyright (c) 2022, 2024 Oracle and/or its affiliates.# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/importosimportrefromdataclassesimportdataclassfromenumimportEnum,autofromfunctoolsimportwrapsfromtypingimportAny,Callable,Dict,Optionalimportads.configfromadsimport__version__fromads.commonimportloggerTELEMETRY_ARGUMENT_NAME="telemetry"LIBRARY="Oracle-ads"EXTRA_USER_AGENT_INFO="EXTRA_USER_AGENT_INFO"USER_AGENT_KEY="additional_user_agent"UNKNOWN="UNKNOWN"DELIMITER="&"
[docs]defupdate_oci_client_config(config:Optional[Dict[str,Any]]=None)->Dict[str,Any]:""" Adds user agent information to the signer config if it is not setup yet. Parameters ---------- config: Dict The signer configuration. Returns ------- Dict The updated configuration. """try:config=configor{}ifnotconfig.get(USER_AGENT_KEY):config.update({USER_AGENT_KEY:(f"{LIBRARY}/version={__version__}#"f"surface={Surface.surface().name}#"f"api={os.environ.get(EXTRA_USER_AGENT_INFO,UNKNOWN)orUNKNOWN}")})exceptExceptionasex:logger.debug(ex)returnconfig
[docs]deftelemetry(entry_point:str="",name:str="",environ_variable:str=EXTRA_USER_AGENT_INFO,)->Callable:""" The telemetry decorator. Injects the Telemetry object into the `kwargs` arguments of the decorated function. This is essential for adding additional information to the telemetry from within the decorated function. Eventually this information will be merged into the `additional_user_agent`. Important Note: The telemetry decorator exclusively updates the specified environment variable and does not perform any additional actions. " Parameters ---------- entry_point: str The entry point of the telemetry. Example: "plugin=project&action=run" name: str The name of the telemetry. environ_variable: (str, optional). Defaults to `EXTRA_USER_AGENT_INFO`. The name of the environment variable to capture the telemetry sequence. Examples -------- >>> @telemetry(entry_point="plugin=project&action=run", name="ads") ... def test_function(**kwargs) ... telemetry = kwargs.get("telemetry") ... telemetry.add("param=hello_world") ... print(telemetry) >>> test_function() ... "ads&plugin=project&action=run¶m=hello_world" """defdecorator(func:Callable)->Callable:@wraps(func)defwrapper(*args,**kwargs)->Any:telemetry=Telemetry(name=name,environ_variable=environ_variable).begin(entry_point)try:# todo: inject telemetry arg and later update all functions that use the @telemetry# decorator to accept **kwargs. Comment the below line as some aqua apis don't support kwargs.# return func(*args, **{**kwargs, **{TELEMETRY_ARGUMENT_NAME: telemetry}})returnfunc(*args,**kwargs)except:raisefinally:telemetry.restore()returnwrapperreturndecorator
[docs]classSurface(Enum):""" An Enum class used to label the surface where ADS is being utilized. """WORKSTATION=auto()DATASCIENCE_JOB=auto()DATASCIENCE_NOTEBOOK=auto()DATASCIENCE_MODEL_DEPLOYMENT=auto()DATAFLOW=auto()OCI_SERVICE=auto()DATASCIENCE_PIPELINE=auto()
[docs]@dataclassclassTelemetry:""" This class is designed to capture a telemetry sequence and store it in the specified environment variable. By default the `EXTRA_USER_AGENT_INFO` environment variable is used. Attributes ---------- name: (str, optional). Default to empty string. The name of the telemetry. The very beginning of the telemetry string. environ_variable: (str, optional). Defaults to `EXTRA_USER_AGENT_INFO`. The name of the environment variable to capture the telemetry sequence. """name:str=""environ_variable:str=EXTRA_USER_AGENT_INFOdef__post_init__(self):self.name=self._prepare(self.name)self._original_value=os.environ.get(self.environ_variable)os.environ[self.environ_variable]=""
[docs]defrestore(self)->"Telemetry":"""Restores the original value of the environment variable. Returns ------- self: Telemetry An instance of the Telemetry. """os.environ[self.environ_variable]=self._original_valueor""returnself
[docs]defclean(self)->"Telemetry":"""Cleans the associated environment variable. Returns ------- self: Telemetry An instance of the Telemetry. """os.environ[self.environ_variable]=""returnself
[docs]defbegin(self,value:str="")->"Telemetry":""" This method should be invoked at the start of telemetry sequence capture. It resets the value of the associated environment variable. Parameters ---------- value: (str, optional). Defaults to empty string. The value that need to be added to the telemetry. Returns ------- self: Telemetry An instance of the Telemetry. """returnself.clean().add(self.name).add(value)
[docs]defadd(self,value:str)->"Telemetry":"""Appends the new value to the telemetry data. Parameters ---------- value: str The value that need to be added to the telemetry. Returns ------- self: Telemetry An instance of the Telemetry. """ifnotos.environ.get(self.environ_variable):self._begin()ifvalue:current_value=os.environ.get(self.environ_variable,"")new_value=self._prepare(value)ifnew_valuenotincurrent_value:os.environ[self.environ_variable]=(f"{current_value}{DELIMITER}{new_value}"ifcurrent_valueelsenew_value)returnself
[docs]defprint(self)->None:"""Prints the telemetry sequence from environment variable."""print(f"{self.environ_variable} = {os.environ.get(self.environ_variable)}")
def_prepare(self,value:str):"""Replaces the special characters with the `_` in the input string."""return(re.sub("[^a-zA-Z0-9\.\-\_\&\=]","_",re.sub(r"\s+"," ",value))ifvalueelse"")