def set_field(self, key, value, obfuscate=False, kind=FieldKind.NORMAL): """Set the value for a field in the event. :param str key: The name of the field. :param value: The value to set the field to. Should be JSON serializable. :param baseplate.events.FieldKind kind: The kind the field is. Used to determine what section of the payload the field belongs in when serialized. """ # There's no need to send null/empty values, the collector will act # the same whether they're sent or not. Zeros are important though, # so we can't use a simple boolean truth check here. if value is None or value == "": return if obfuscate: kind = FieldKind.OBFUSCATED warn_deprecated("Passing obfuscate to set_field is deprecated in" " favor of passing a FieldKind value as kind.") self.payload[key] = value self.payload_types[key] = kind
def configure_tracing(self, tracing_client, *args, **kwargs): """Collect and send span information for request tracing. When configured, this will send tracing information automatically collected by Baseplate to the configured distributed tracing service. :param baseplate.diagnostics.tracing.TracingClient tracing_client: Tracing client to send request traces to. """ # pylint: disable=cyclic-import from baseplate.diagnostics.tracing import make_client, TraceBaseplateObserver, TracingClient # the first parameter was service_name before, so if it's not a client # object we'll act like this is the old-style invocation and use the # first parameter as service_name instead, passing on the old arguments if not isinstance(tracing_client, TracingClient): warn_deprecated( "Passing tracing configuration directly to " "configure_tracing is deprecated in favor of " "using baseplate.tracing_client_from_config and " "passing the constructed client on." ) tracing_client = make_client(tracing_client, *args, **kwargs) self.register(TraceBaseplateObserver(tracing_client))
def __init__(self, secret_key): warn_deprecated( "MessageSigner is deprecated in favor of the top-level " "make_signature and validate_signature functions which " "accept versioned secrets from the secret store." ) self.secret = VersionedSecret.from_simple_secret(secret_key)
def make_client( service_name, tracing_endpoint=None, tracing_queue_name=None, max_span_queue_size=50000, num_span_workers=5, span_batch_interval=0.5, num_conns=100, sample_rate=0.1, log_if_unconfigured=True, ): """Create and return a tracing client based on configuration options. This client can be used by the :py:class:`TraceBaseplateObserver`. :param str service_name: The name for the service this observer is registered to. :param baseplate.config.EndpointConfiguration tracing_endpoint: destination to record span data. :param str tracing_queue_name: POSIX queue name for reporting spans. :param int num_conns: pool size for remote recorder connection pool. :param int max_span_queue_size: span processing queue limit. :param int num_span_workers: number of worker threads for span processing. :param float span_batch_interval: wait time for span processing in seconds. :param float sample_rate: percentage of unsampled requests to record traces for. """ if tracing_queue_name: logger.info("Recording spans to queue %s", tracing_queue_name) recorder = SidecarRecorder(tracing_queue_name) elif tracing_endpoint: warn_deprecated( "In-app trace publishing is deprecated in favor of the sidecar model." ) remote_addr = "%s:%s" % tracing_endpoint.address logger.info("Recording spans to %s", remote_addr) recorder = RemoteRecorder( remote_addr, num_conns=num_conns, max_queue_size=max_span_queue_size, num_workers=num_span_workers, batch_wait_interval=span_batch_interval, ) elif log_if_unconfigured: recorder = LoggingRecorder( max_queue_size=max_span_queue_size, num_workers=num_span_workers, batch_wait_interval=span_batch_interval, ) else: recorder = NullRecorder( max_queue_size=max_span_queue_size, num_workers=num_span_workers, batch_wait_interval=span_batch_interval, ) return TracingClient(service_name, sample_rate, recorder)
def __init__( self, baseplate, trust_trace_headers=None, edge_context_factory=None, header_trust_handler=None, ): self.baseplate = baseplate self.trust_trace_headers = bool(trust_trace_headers) if trust_trace_headers is not None: warn_deprecated( "setting trust_trace_headers is deprecated in favor of using" " a header trust handler.") self.edge_context_factory = edge_context_factory if header_trust_handler: self.header_trust_handler = header_trust_handler else: self.header_trust_handler = StaticTrustHandler( trust_headers=self.trust_trace_headers)
def constant_time_compare(actual, expected): """Return whether or not two strings match. The time taken is dependent on the number of characters provided instead of the number of characters that match which makes this function resistant to timing attacks. """ if type(actual) != type(expected): warn_deprecated( "Future versions of constant_time_compare require that both " "parameters are of the same type.") actual_len = len(actual) expected_len = len(expected) result = actual_len ^ expected_len if expected_len > 0: for i in xrange(actual_len): result |= ord(actual[i]) ^ ord(expected[i % expected_len]) return result == 0
def make_metrics_client(raw_config: config.RawConfig) -> metrics.Client: warn_deprecated("make_metrics_client is deprecated in favor of the more " "consistently named metrics_client_from_config") return metrics_client_from_config(raw_config)
def make_tracing_client( raw_config: config.RawConfig, log_if_unconfigured: bool = True) -> tracing.TracingClient: warn_deprecated("make_tracing_client is deprecated in favor of the more " "consistently named tracing_client_from_config") return tracing_client_from_config(raw_config, log_if_unconfigured)
def parse_experiment(config): """Parse an experiment config dict and return an appropriate Experiment class. The config dict is expected to have the following values: * **id**: Integer experiment ID, should be unique for each experiment. * **name**: String experiment name, should be unique for each experiment. * **owner**: The group or individual that owns this experiment. * **version**: String to identify the specific version of the experiment. * **start_ts**: A float of seconds since the epoch of date and time when you want the experiment to start. If an experiment has not been started yet, it is considered disabled. * **stop_ts**: A float of seconds since the epoch of date and time when you want the experiment to stop. Once an experiment is stopped, it is considered disabled. * **type**: String specifying the type of experiment to run. If this value is not recognized, the experiment will be considered disabled. * **experiment**: The experiment config dict for the specific type of experiment. The format of this is determined by the specific experiment type. * **enabled**: (Optional) If set to False, the experiment will be disabled and calls to experiment.variant will always return None and will not log bucketing events to the event pipeline. Defaults to True. * **global_override**: (Optional) If this is set, calls to experiment.variant will always return the override value and will not log bucketing events to the event pipeline. :param dict config: Configuration dict for the experiment you wish to run. :rtype: :py:class:`baseplate.experiments.providers.base.Experiment` :return: A subclass of :py:class:`Experiment` for the given experiment type. """ experiment_type = config.get("type") if experiment_type: experiment_type = experiment_type.lower() experiment_id = config.get("id") if not isinstance(experiment_id, int): raise TypeError("Integer id must be provided for experiment.") name = config.get("name") owner = config.get("owner") start_ts = config.get("start_ts") stop_ts = config.get("stop_ts") if start_ts is None or stop_ts is None: if "expires" in config: warn_deprecated( "The 'expires' field in experiment %s is deprecated, you should " "use 'start_ts' and 'stop_ts'." % name ) start_ts = time.time() expires = datetime.strptime(config["expires"], ISO_DATE_FMT) epoch = datetime(1970, 1, 1) stop_ts = (expires - epoch).total_seconds() else: raise ValueError( "Invalid config for experiment %s, missing start_ts and/or " "stop_ts." % name ) if "version" in config: version = config["version"] else: warn_deprecated( "The 'version' field is not in experiment %s. This field will be " "required in the future." % name ) version = None now = time.time() enabled = config.get("enabled", True) if now < start_ts or now > stop_ts: enabled = False if not enabled and experiment_type in legacy_type_class_map: return ForcedVariantExperiment(None) experiment_config = config["experiment"] if "global_override" in config: # We want to check if "global_override" is in config rather than # checking config.get("global_override") because global_override = None # is a valid setting. override = config.get("global_override") return ForcedVariantExperiment(override) if experiment_type in legacy_type_class_map: experiment_class = legacy_type_class_map[experiment_type] return experiment_class.from_dict( id=experiment_id, name=name, owner=owner, version=version, config=experiment_config ) if experiment_type in simple_type_class_list: return SimpleExperiment.from_dict( id=experiment_id, name=name, owner=owner, start_ts=start_ts, stop_ts=stop_ts, enabled=enabled, config=experiment_config, variant_type=experiment_type, ) logger.warning( "Found an experiment <%s:%s> with an unknown experiment type <%s> " "that is owned by <%s>. Please clean up.", experiment_id, name, experiment_type, owner, ) return ForcedVariantExperiment(None)
def __init__(self, secret_key): warn_deprecated("MessageSigner is deprecated in favor of the top-level " "make_signature and validate_signature functions which " "accept versioned secrets from the secret store.") self.secret = VersionedSecret.from_simple_secret(secret_key)
def make_tracing_client(raw_config, log_if_unconfigured=True): warn_deprecated("make_tracing_client is deprecated in favor of the more " "consistently named tracing_client_from_config") return tracing_client_from_config(raw_config, log_if_unconfigured)