Exemplo n.º 1
0
    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
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
    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))
Exemplo n.º 4
0
 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)
Exemplo n.º 5
0
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)
Exemplo n.º 6
0
    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)
Exemplo n.º 7
0
    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
Exemplo n.º 8
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)
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
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)
Exemplo n.º 11
0
 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)
Exemplo n.º 12
0
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)