def METHOD_NAME(func, instance, args, kwargs):
    pin = Pin.get_from(instance)
    if not pin or not pin.enabled():
        return func(*args, **kwargs)
    with pin.tracer.trace(
        "elasticsearch.query", service=ext_service(pin, config.elasticsearch), span_type=SpanTypes.ELASTICSEARCH
    ) as span:
        span.set_tag_str(COMPONENT, config.elasticsearch.integration_name)
        # set span.kind to the type of request being performed
        span.set_tag_str(SPAN_KIND, SpanKind.CLIENT)
        span.set_tag(SPAN_MEASURED_KEY)
        # Don't instrument if the trace is not sampled
        if not span.sampled:
            return func(*args, **kwargs)
        method, url = args
        params = kwargs.get("params") or {}
        encoded_params = urlencode(params)
        body = kwargs.get("body")
        span.set_tag_str(metadata.METHOD, method)
        span.set_tag_str(metadata.URL, url)
        span.set_tag_str(metadata.PARAMS, encoded_params)
        for connection in instance.connection_pool.connections:
            hostname, _ = extract_netloc_and_query_info_from_url(connection.host)
            if hostname:
                span.set_tag_str(net.TARGET_HOST, hostname)
                break
        if config.elasticsearch.trace_query_string:
            span.set_tag_str(http.QUERY_STRING, encoded_params)
        if method in ["GET", "POST"]:
            ser_body = instance.serializer.dumps(body)
            # Elasticsearch request bodies can be very large resulting in traces being too large
            # to send.
            # When this occurs, drop the value.
            # Ideally the body should be truncated, however we cannot truncate as the obfuscation
            # logic for the body lives in the agent and truncating would make the body undecodable.
            if len(ser_body) <= _limits.MAX_SPAN_META_VALUE_LEN:
                span.set_tag_str(metadata.BODY, ser_body)
            else:
                span.set_tag_str(
                    metadata.BODY,
                    "<body size %s exceeds limit of %s>" % (len(ser_body), _limits.MAX_SPAN_META_VALUE_LEN),
                )
        status = None
        # set analytics sample rate
        span.set_tag(ANALYTICS_SAMPLE_RATE_KEY, config.elasticsearch.get_analytics_sample_rate())
        span = quantize(span)
        try:
            result = func(*args, **kwargs)
        except elasticsearch.exceptions.TransportError as e:
            span.set_tag(http.STATUS_CODE, getattr(e, "status_code", 500))
            span.error = 1
            raise
        try:
            # Optional metadata extraction with soft fail.
            if isinstance(result, tuple) and len(result) == 2:
                # elasticsearch<2.4; it returns both the status and the body
                status, data = result
            else:
                # elasticsearch>=2.4; internal change for ``Transport.perform_request``
                # that just returns the body
                data = result
            took = data.get("took")
            if took:
                span.set_metric(metadata.TOOK, int(took))
        except Exception:
            log.debug("Unexpected exception", exc_info=True)
        if status:
            span.set_tag(http.STATUS_CODE, status)
        return result