def test_transmission_206_500(self):
     test_envelope = TelemetryItem(name="testEnvelope", time=datetime.now())
     custom_envelopes_to_export = [
         TelemetryItem(name="Test", time=datetime.now()),
         TelemetryItem(name="Test", time=datetime.now()), test_envelope
     ]
     with mock.patch("requests.Session.request") as post:
         post.return_value = MockResponse(
             206,
             json.dumps({
                 "itemsReceived":
                 5,
                 "itemsAccepted":
                 3,
                 "errors": [
                     {
                         "index": 0,
                         "statusCode": 400,
                         "message": ""
                     },
                     {
                         "index": 2,
                         "statusCode": 500,
                         "message": "Internal Server Error",
                     },
                 ],
             }),
         )
         result = self._base._transmit(custom_envelopes_to_export)
     self.assertEqual(result, ExportResult.FAILED_RETRYABLE)
     self._base.storage.get()
     self.assertEqual(self._base.storage.get().get()[0]["name"],
                      "testEnvelope")
 def setUpClass(cls):
     os.environ[
         "APPINSIGHTS_INSTRUMENTATIONKEY"] = "1234abcd-5678-4efa-8abc-1234567890ab"
     cls._base = BaseExporter()
     cls._envelopes_to_export = [
         TelemetryItem(name="Test", time=datetime.now())
     ]
Beispiel #3
0
 def _transmit_from_storage(self) -> None:
     for blob in self.storage.gets():
         # give a few more seconds for blob lease operation
         # to reduce the chance of race (for perf consideration)
         if blob.lease(self._timeout + 5):
             envelopes = [TelemetryItem(**x) for x in blob.get()]
             result = self._transmit(list(envelopes))
             if result == ExportResult.FAILED_RETRYABLE:
                 blob.lease(1)
             else:
                 blob.delete()
def _convert_log_to_envelope(log_data: LogData) -> TelemetryItem:
    log_record = log_data.log_record
    envelope = TelemetryItem(
        name="",
        instrumentation_key="",
        tags=dict(_utils.azure_monitor_context),
        time=ns_to_iso_str(log_record.timestamp),
    )
    envelope.tags.update(_utils._populate_part_a_fields(log_record.resource))
    envelope.tags["ai.operation.id"] = "{:032x}".format(
        log_record.trace_id or _DEFAULT_TRACE_ID
    )
    envelope.tags["ai.operation.parentId"] = "{:016x}".format(
        log_record.span_id or _DEFAULT_SPAN_ID
    )
    properties = {
        k: v
        for k, v in log_record.attributes.items()
        if k not in _EXCEPTION_ATTRS
    }
    exc_type = log_record.attributes.get(SpanAttributes.EXCEPTION_TYPE)
    exc_message = log_record.attributes.get(SpanAttributes.EXCEPTION_MESSAGE)
    # pylint: disable=line-too-long
    stack_trace = log_record.attributes.get(SpanAttributes.EXCEPTION_STACKTRACE)
    severity_level = _get_severity_level(log_record.severity_number)

    # Exception telemetry
    if exc_type is not None or exc_message is not None:
        envelope.name = "Microsoft.ApplicationInsights.Exception"
        has_full_stack = stack_trace is not None
        exc_details = TelemetryExceptionDetails(
            type_name=exc_type,
            message=exc_message,
            has_full_stack=has_full_stack,
            stack=stack_trace,
        )
        data = TelemetryExceptionData(
            severity_level=severity_level,
            properties=properties,
            exceptions=[exc_details],
        )
        # pylint: disable=line-too-long
        envelope.data = MonitorBase(base_data=data, base_type="TelemetryExceptionData")
    else:  # Message telemetry
        envelope.name = "Microsoft.ApplicationInsights.Message"
        # pylint: disable=line-too-long
        # Severity number: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#field-severitynumber
        data = MessageData(
            message=log_record.body,
            severity_level=severity_level,
            properties=properties,
        )
        envelope.data = MonitorBase(base_data=data, base_type="MessageData")

    return envelope
Beispiel #5
0
 def test_transmission_206_bogus(self):
     envelopes_to_export = map(lambda x: x.as_dict(), tuple(
         [TelemetryItem(name="testEnvelope", time=datetime.now())]))
     self._base.storage.put(envelopes_to_export)
     with mock.patch("requests.Session.request") as post:
         post.return_value = MockResponse(
             206,
             json.dumps(
                 {
                     "itemsReceived": 5,
                     "itemsAccepted": 3,
                     "errors": [{"foo": 0, "bar": 1}],
                 }
             ),
         )
         result = self._base._transmit(self._envelopes_to_export)
     self.assertEqual(result, ExportResult.FAILED_NOT_RETRYABLE)
def _convert_span_to_envelope(span: Span) -> TelemetryItem:
    envelope = TelemetryItem(
        name="",
        instrumentation_key="",
        tags=dict(_utils.azure_monitor_context),
        time=ns_to_iso_str(span.start_time),
    )
    if span.resource and span.resource.attributes:
        service_name = span.resource.attributes.get(ResourceAttributes.SERVICE_NAME)
        service_namespace = span.resource.attributes.get(ResourceAttributes.SERVICE_NAMESPACE)
        service_instance_id = span.resource.attributes.get(ResourceAttributes.SERVICE_INSTANCE_ID)
        if service_name:
            if service_namespace:
                envelope.tags["ai.cloud.role"] = service_namespace + \
                    "." + service_name
            else:
                envelope.tags["ai.cloud.role"] = service_name
        if service_instance_id:
            envelope.tags["ai.cloud.roleInstance"] = service_instance_id
        else:
            envelope.tags["ai.cloud.roleInstance"] = platform.node()  # hostname default
        envelope.tags["ai.internal.nodeName"] = envelope.tags["ai.cloud.roleInstance"]
    envelope.tags["ai.operation.id"] = "{:032x}".format(span.context.trace_id)
    if SpanAttributes.ENDUSER_ID in span.attributes:
        envelope.tags["ai.user.id"] = span.attributes[SpanAttributes.ENDUSER_ID]
    if span.parent and span.parent.span_id:
        envelope.tags["ai.operation.parentId"] = "{:016x}".format(
            span.parent.span_id
        )
    # pylint: disable=too-many-nested-blocks
    if span.kind in (SpanKind.CONSUMER, SpanKind.SERVER):
        envelope.name = "Microsoft.ApplicationInsights.Request"
        data = RequestData(
            name=span.name,
            id="{:016x}".format(span.context.span_id),
            duration=_utils.ns_to_duration(span.end_time - span.start_time),
            response_code="0",
            success=span.status.is_ok,
            properties={},
        )
        envelope.data = MonitorBase(base_data=data, base_type="RequestData")
        if SpanAttributes.HTTP_METHOD in span.attributes:  # HTTP
            url = ""
            path = ""
            if SpanAttributes.HTTP_USER_AGENT in span.attributes:
                # TODO: Not exposed in Swagger, need to update def
                envelope.tags["ai.user.userAgent"] = span.attributes[SpanAttributes.HTTP_USER_AGENT]
            if SpanAttributes.HTTP_CLIENT_IP in span.attributes:
                envelope.tags["ai.location.ip"] = span.attributes[SpanAttributes.HTTP_CLIENT_IP]
            elif SpanAttributes.NET_PEER_IP in span.attributes:
                envelope.tags["ai.location.ip"] = span.attributes[SpanAttributes.NET_PEER_IP]
            # url
            if SpanAttributes.HTTP_URL in span.attributes:
                url = span.attributes[SpanAttributes.HTTP_URL]
            elif SpanAttributes.HTTP_SCHEME in span.attributes and SpanAttributes.HTTP_TARGET in span.attributes:
                scheme = span.attributes[SpanAttributes.HTTP_SCHEME]
                http_target = span.attributes[SpanAttributes.HTTP_TARGET]
                if SpanAttributes.HTTP_HOST in span.attributes:
                    url = "{}://{}{}".format(
                        scheme,
                        span.attributes[SpanAttributes.HTTP_HOST],
                        http_target,
                    )
                elif SpanAttributes.NET_HOST_PORT in span.attributes:
                    host_port = span.attributes[SpanAttributes.NET_HOST_PORT]
                    if SpanAttributes.HTTP_SERVER_NAME in span.attributes:
                        server_name = span.attributes[SpanAttributes.HTTP_SERVER_NAME]
                        url = "{}://{}:{}{}".format(
                            scheme,
                            server_name,
                            host_port,
                            http_target,
                        )
                    elif SpanAttributes.NET_HOST_NAME in span.attributes:
                        host_name = span.attributes[SpanAttributes.NET_HOST_NAME]
                        url = "{}://{}:{}{}".format(
                            scheme,
                            host_name,
                            host_port,
                            http_target,
                        )
            data.url = url
            # Http specific logic for ai.operation.name
            if SpanAttributes.HTTP_ROUTE in span.attributes:
                envelope.tags["ai.operation.name"] = "{} {}".format(
                    span.attributes[SpanAttributes.HTTP_METHOD],
                    span.attributes[SpanAttributes.HTTP_ROUTE],
                )
            elif url:
                try:
                    parse_url = urlparse(url)
                    path = parse_url.path
                    if not path:
                        path = "/"
                    envelope.tags["ai.operation.name"] = "{} {}".format(
                        span.attributes[SpanAttributes.HTTP_METHOD],
                        path,
                    )
                except Exception:  # pylint: disable=broad-except
                    pass
            else:
                envelope.tags["ai.operation.name"] = span.name
            if SpanAttributes.HTTP_STATUS_CODE in span.attributes:
                status_code = span.attributes[SpanAttributes.HTTP_STATUS_CODE]
                data.response_code = str(status_code)
        elif SpanAttributes.MESSAGING_SYSTEM in span.attributes:  # Messaging
            envelope.tags["ai.operation.name"] = span.name
            if SpanAttributes.NET_PEER_IP in span.attributes:
                envelope.tags["ai.location.ip"] = span.attributes[SpanAttributes.NET_PEER_IP]
            if SpanAttributes.MESSAGING_DESTINATION in span.attributes:
                if SpanAttributes.NET_PEER_NAME in span.attributes:
                    data.properties["source"] = "{}/{}".format(
                        span.attributes[SpanAttributes.NET_PEER_NAME],
                        span.attributes[SpanAttributes.MESSAGING_DESTINATION],
                    )
                elif SpanAttributes.NET_PEER_IP in span.attributes:
                    data.properties["source"] = "{}/{}".format(
                        span.attributes[SpanAttributes.NET_PEER_IP],
                        span.attributes[SpanAttributes.MESSAGING_DESTINATION],
                    )
                else:
                    data.properties["source"] = span.attributes[SpanAttributes.MESSAGING_DESTINATION]
        else:  # Other
            envelope.tags["ai.operation.name"] = span.name
            if SpanAttributes.NET_PEER_IP in span.attributes:
                envelope.tags["ai.location.ip"] = span.attributes[SpanAttributes.NET_PEER_IP]
        # Apply truncation
        if data.url:
            data.url = data.url[:2048]  # Breeze max length
        if data.response_code:
            data.response_code = data.response_code[:1024]  # Breeze max length
        if envelope.tags["ai.operation.name"]:
            data.name = envelope.tags["ai.operation.name"][:1024]  # Breeze max length
    else:  # INTERNAL, CLIENT, PRODUCER
        envelope.name = "Microsoft.ApplicationInsights.RemoteDependency"
        # TODO: ai.operation.name for non-server spans
        data = RemoteDependencyData(
            name=span.name,
            id="{:016x}".format(span.context.span_id),
            result_code="0",
            duration=_utils.ns_to_duration(span.end_time - span.start_time),
            success=span.status.is_ok,
            properties={},
        )
        envelope.data = MonitorBase(
            base_data=data, base_type="RemoteDependencyData"
        )
        target = None
        if SpanAttributes.PEER_SERVICE in span.attributes:
            target = span.attributes[SpanAttributes.PEER_SERVICE]
        else:
            if SpanAttributes.NET_PEER_NAME in span.attributes:
                target = span.attributes[SpanAttributes.NET_PEER_NAME]
            elif SpanAttributes.NET_PEER_IP in span.attributes:
                target = span.attributes[SpanAttributes.NET_PEER_IP]
            if SpanAttributes.NET_PEER_PORT in span.attributes:
                port = span.attributes[SpanAttributes.NET_PEER_PORT]
                # TODO: check default port for rpc
                # This logic assumes default ports never conflict across dependency types
                if port != _get_default_port_http(span.attributes.get(SpanAttributes.HTTP_SCHEME)) and \
                    port != _get_default_port_db(span.attributes.get(SpanAttributes.DB_SYSTEM)):
                    target = "{}:{}".format(target, port)
        if span.kind is SpanKind.CLIENT:
            if SpanAttributes.HTTP_METHOD in span.attributes:  # HTTP
                data.type = "HTTP"
                if SpanAttributes.HTTP_USER_AGENT in span.attributes:
                    # TODO: Not exposed in Swagger, need to update def
                    envelope.tags["ai.user.userAgent"] = span.attributes[SpanAttributes.HTTP_USER_AGENT]
                scheme = span.attributes.get(SpanAttributes.HTTP_SCHEME)
                # url
                url = ""
                if SpanAttributes.HTTP_URL in span.attributes:
                    url = span.attributes[SpanAttributes.HTTP_URL]
                elif scheme and SpanAttributes.HTTP_TARGET in span.attributes:
                    http_target = span.attributes[SpanAttributes.HTTP_TARGET]
                    if SpanAttributes.HTTP_HOST in span.attributes:
                        url = "{}://{}{}".format(
                            scheme,
                            span.attributes[SpanAttributes.HTTP_HOST],
                            http_target,
                        )
                    elif SpanAttributes.NET_PEER_PORT in span.attributes:
                        peer_port = span.attributes[SpanAttributes.NET_PEER_PORT]
                        if SpanAttributes.NET_PEER_NAME in span.attributes:
                            peer_name = span.attributes[SpanAttributes.NET_PEER_NAME]
                            url = "{}://{}:{}{}".format(
                                scheme,
                                peer_name,
                                peer_port,
                                http_target,
                            )
                        elif SpanAttributes.NET_PEER_IP in span.attributes:
                            peer_ip = span.attributes[SpanAttributes.NET_PEER_IP]
                            url = "{}://{}:{}{}".format(
                                scheme,
                                peer_ip,
                                peer_port,
                                http_target,
                            )
                target_from_url = ""
                path = ""
                if url:
                    try:
                        parse_url = urlparse(url)
                        path = parse_url.path
                        if not path:
                            path = "/"
                        if parse_url.port == _get_default_port_http(scheme):
                            target_from_url = parse_url.hostname
                        else:
                            target_from_url = parse_url.netloc
                    except Exception:  # pylint: disable=broad-except
                        pass
                # http specific logic for name
                if path:
                    data.name = "{} {}".format(
                        span.attributes[SpanAttributes.HTTP_METHOD],
                        path,
                    )
                # http specific logic for target
                if SpanAttributes.PEER_SERVICE not in span.attributes:
                    if SpanAttributes.HTTP_HOST in span.attributes:
                        host = span.attributes[SpanAttributes.HTTP_HOST]
                        try:
                            # urlparse insists on absolute URLs starting with "//"
                            # This logic assumes host does not include a "//"
                            host_name = urlparse("//" + host)
                            if host_name.port == _get_default_port_http(scheme):
                                target = host_name.hostname
                            else:
                                target = host
                        except Exception:  # pylint: disable=broad-except
                            logger.warning("Error while parsing hostname.")
                    elif target_from_url:
                        target = target_from_url
                # data is url
                data.data = url
                if SpanAttributes.HTTP_STATUS_CODE in span.attributes:
                    status_code = span.attributes[SpanAttributes.HTTP_STATUS_CODE]
                    data.result_code = str(status_code)
            elif SpanAttributes.DB_SYSTEM in span.attributes:  # Database
                db_system = span.attributes[SpanAttributes.DB_SYSTEM]
                if not _is_sql_db(db_system):
                    data.type = db_system
                else:
                    data.type = "SQL"
                # data is the full statement or operation
                if SpanAttributes.DB_STATEMENT in span.attributes:
                    data.data = span.attributes[SpanAttributes.DB_STATEMENT]
                elif SpanAttributes.DB_OPERATION in span.attributes:
                    data.data = span.attributes[SpanAttributes.DB_OPERATION]
                # db specific logic for target
                if SpanAttributes.DB_NAME in span.attributes:
                    db_name = span.attributes[SpanAttributes.DB_NAME]
                    if target is None:
                        target = db_name
                    else:
                        target = "{}|{}".format(target, db_name)
                if target is None:
                    target = db_system
            elif SpanAttributes.RPC_SYSTEM in span.attributes:  # Rpc
                data.type = SpanAttributes.RPC_SYSTEM
                # TODO: data.data for rpc
                if target is None:
                    target = span.attributes[SpanAttributes.RPC_SYSTEM]
            else:
                # TODO: Azure specific types
                data.type = "N/A"
        elif span.kind is SpanKind.PRODUCER:  # Messaging
            data.type = "Queue Message"
            # TODO: data.data for messaging
            # TODO: Special logic for data.target for messaging?
        else:  # SpanKind.INTERNAL
            if span.parent:
                data.type = "InProc"
            data.success = True
        # Apply truncation
        if data.result_code:
            data.result_code = data.result_code[:1024]
        if data.data:
            data.data = data.data[:8192]
        if target:
            data.target = target[:1024]
        if data.name:
            data.name = data.name[:1024]
    for key, val in span.attributes.items():
        # Remove Opentelemetry related span attributes from custom dimensions
        if key.startswith("http.") or \
                key.startswith("db.") or \
                key.startswith("rpc.") or \
                key.startswith("net.") or \
                key.startswith("messaging."):
            continue
        # Apply truncation rules
        # Max key length is 150, value is 8192
        if not key or len(key) > 150 or val is None:
            continue
        data.properties[key] = val[:8192]
    if span.links:
        # Max length for value is 8192
        # Since links are a fixed length (80) in json, max number of links would be 102
        links = []
        for link in span.links:
            if len(links) > 102:
                break
            operation_id = "{:032x}".format(link.context.trace_id)
            span_id = "{:016x}".format(link.context.span_id)
            links.append({"operation_Id": operation_id, "id": span_id})
        data.properties["_MS.links"] = json.dumps(links)
    return envelope
Beispiel #7
0
def _convert_span_to_envelope(span: Span) -> TelemetryItem:
    envelope = TelemetryItem(
        name="",
        instrumentation_key="",
        tags=dict(_utils.azure_monitor_context),
        time=ns_to_iso_str(span.start_time),
    )
    if span.resource and span.resource.attributes:
        service_name = span.resource.attributes.get("service.name")
        service_namespace = span.resource.attributes.get("service.namespace")
        service_instance_id = span.resource.attributes.get(
            "service.instance.id")
        if service_name:
            if service_namespace:
                envelope.tags["ai.cloud.role"] = service_namespace + \
                    "." + service_name
            else:
                envelope.tags["ai.cloud.role"] = service_name
        if service_instance_id:
            envelope.tags["ai.cloud.roleInstance"] = service_instance_id
        else:
            envelope.tags["ai.cloud.roleInstance"] = platform.node(
            )  # hostname default
        envelope.tags["ai.internal.nodeName"] = envelope.tags[
            "ai.cloud.roleInstance"]
    envelope.tags["ai.operation.id"] = "{:032x}".format(span.context.trace_id)
    if "enduser.id" in span.attributes:
        envelope.tags["ai.user.id"] = span.attributes["enduser.id"]
    if span.parent:
        envelope.tags["ai.operation.parentId"] = "{:016x}".format(
            span.parent.span_id)
    # pylint: disable=too-many-nested-blocks
    if span.kind in (SpanKind.CONSUMER, SpanKind.SERVER):
        envelope.name = "Microsoft.ApplicationInsights.Request"
        data = RequestData(
            name=span.name[:1024],  # Breeze max length
            id="{:016x}".format(span.context.span_id),
            duration=_utils.ns_to_duration(span.end_time - span.start_time),
            response_code="0",
            success=span.status.is_ok,
            properties={},
        )
        envelope.data = MonitorBase(base_data=data, base_type="RequestData")
        if "http.method" in span.attributes:  # HTTP
            envelope.tags["ai.operation.name"] = "{} {}".format(
                span.attributes["http.method"],
                span.name,
            )
            data.properties["request.name"] = data.name
            url = ""
            if "http.user_agent" in span.attributes:
                # TODO: Not exposed in Swagger, need to update def
                envelope.tags["ai.user.userAgent"] = span.attributes[
                    "http.user_agent"]
            if "http.client_ip" in span.attributes:
                envelope.tags["ai.location.ip"] = span.attributes[
                    "http.client_ip"]
            elif "net.peer.ip" in span.attributes:
                envelope.tags["ai.location.ip"] = span.attributes[
                    "net.peer.ip"]
            # url
            if "http.url" in span.attributes:
                url = span.attributes["http.url"]
            elif "http.scheme" in span.attributes and "http.target" in span.attributes:
                scheme = span.attributes["http.scheme"]
                http_target = span.attributes["http.target"]
                if "http.host" in span.attributes:
                    url = "{}://{}{}".format(
                        scheme,
                        span.attributes["http.host"],
                        http_target,
                    )
                elif "net.host.port" in span.attributes:
                    host_port = span.attributes["net.host.port"]
                    if "http.server_name" in span.attributes:
                        server_name = span.attributes["http.server_name"]
                        url = "{}://{}:{}{}".format(
                            scheme,
                            server_name,
                            host_port,
                            http_target,
                        )
                    elif "net.host.name" in span.attributes:
                        host_name = span.attributes["net.host.name"]
                        url = "{}://{}:{}{}".format(
                            scheme,
                            host_name,
                            host_port,
                            http_target,
                        )
            if url:
                url = url[:2048]  # Breeze max length
            data.url = url
            data.properties["request.url"] = url
            if "http.status_code" in span.attributes:
                status_code = span.attributes["http.status_code"]
                data.response_code = str(status_code)
        elif "messaging.system" in span.attributes:  # Messaging
            envelope.tags["ai.operation.name"] = span.name
            if "net.peer.ip" in span.attributes:
                envelope.tags["ai.location.ip"] = span.attributes[
                    "net.peer.ip"]
            if "messaging.destination" in span.attributes:
                if "net.peer.name" in span.attributes:
                    data.properties["source"] = "{}/{}".format(
                        span.attributes["net.peer.name"],
                        span.attributes["messaging.destination"],
                    )
                elif "net.peer.ip" in span.attributes:
                    data.properties["source"] = "{}/{}".format(
                        span.attributes["net.peer.ip"],
                        span.attributes["messaging.destination"],
                    )
                else:
                    data.properties["source"] = span.attributes[
                        "messaging.destination"]
        else:  # Other
            envelope.tags["ai.operation.name"] = span.name
            if "net.peer.ip" in span.attributes:
                envelope.tags["ai.location.ip"] = span.attributes[
                    "net.peer.ip"]
        data.response_code = data.response_code[:1024]  # Breeze max length
    else:  # INTERNAL, CLIENT, PRODUCER
        envelope.name = "Microsoft.ApplicationInsights.RemoteDependency"
        # TODO: ai.operation.name for non-server spans
        data = RemoteDependencyData(
            name=span.name[:1024],  # Breeze max length
            id="{:016x}".format(span.context.span_id),
            result_code=str(span.status.status_code.value),
            duration=_utils.ns_to_duration(span.end_time - span.start_time),
            success=span.status.is_ok,
            properties={},
        )
        envelope.data = MonitorBase(base_data=data,
                                    base_type="RemoteDependencyData")
        target = None
        if "peer.service" in span.attributes:
            target = span.attributes["peer.service"]
        else:
            if "net.peer.name" in span.attributes:
                target = span.attributes["net.peer.name"]
            elif "net.peer.ip" in span.attributes:
                target = span.attributes["net.peer.ip"]
            if "net.peer.port" in span.attributes:
                port = span.attributes["net.peer.port"]
                # TODO: check default port for rpc
                # This logic assumes default ports never conflict across dependency types
                if port != _get_default_port_http(span.attributes.get("http.scheme")) and \
                    port != _get_default_port_db(span.attributes.get("db.system")):
                    target = "{}:{}".format(target, port)
        if span.kind is SpanKind.CLIENT:
            if "http.method" in span.attributes:  # HTTP
                data.type = "HTTP"
                if "http.user_agent" in span.attributes:
                    # TODO: Not exposed in Swagger, need to update def
                    envelope.tags["ai.user.userAgent"] = span.attributes[
                        "http.user_agent"]
                scheme = span.attributes.get("http.scheme")
                url = ""
                # Target
                if "http.url" in span.attributes:
                    url = span.attributes["http.url"]
                    # http specific logic for target
                    if "peer.service" not in span.attributes:
                        try:
                            parse_url = urlparse(url)
                            if parse_url.port == _get_default_port_http(
                                    scheme):
                                target = parse_url.hostname
                            else:
                                target = parse_url.netloc
                        except Exception:  # pylint: disable=broad-except
                            logger.warning("Error while parsing url.")
                # http specific logic for target
                if "peer.service" not in span.attributes and "http.host" in span.attributes:
                    host = span.attributes["http.host"]
                    try:
                        # urlparse insists on absolute URLs starting with "//"
                        # This logic assumes host does not include a "//"
                        host_name = urlparse("//" + host)
                        if host_name.port == _get_default_port_http(scheme):
                            target = host_name.hostname
                        else:
                            target = host
                    except Exception:  # pylint: disable=broad-except
                        logger.warning("Error while parsing hostname.")
                # url
                if not url:
                    if scheme and "http.target" in span.attributes:
                        http_target = span.attributes["http.target"]
                        if "http.host" in span.attributes:
                            url = "{}://{}{}".format(
                                scheme,
                                span.attributes["http.host"],
                                http_target,
                            )
                        elif "net.peer.port" in span.attributes:
                            peer_port = span.attributes["net.peer.port"]
                            if "net.peer.name" in span.attributes:
                                peer_name = span.attributes["net.peer.name"]
                                url = "{}://{}:{}{}".format(
                                    scheme,
                                    peer_name,
                                    peer_port,
                                    http_target,
                                )
                            elif "net.peer.ip" in span.attributes:
                                peer_ip = span.attributes["net.peer.ip"]
                                url = "{}://{}:{}{}".format(
                                    scheme,
                                    peer_ip,
                                    peer_port,
                                    http_target,
                                )
                # data is url
                data.data = url
                if "http.status_code" in span.attributes:
                    status_code = span.attributes["http.status_code"]
                    data.result_code = str(status_code)
            elif "db.system" in span.attributes:  # Database
                db_system = span.attributes["db.system"]
                if _is_relational_db(db_system):
                    data.type = "SQL"
                else:
                    data.type = db_system
                # data is the full statement
                if "db.statement" in span.attributes:
                    data.data = span.attributes["db.statement"]
                # db specific logic for target
                if "db.name" in span.attributes:
                    db_name = span.attributes["db.name"]
                    if target is None:
                        target = db_name
                    else:
                        target = "{}/{}".format(target, db_name)
                if target is None:
                    target = db_system
            elif "rpc.system" in span.attributes:  # Rpc
                data.type = "rpc.system"
                # TODO: data.data for rpc
                # rpc specific logic for target
                if "peer.service" not in span.attributes:
                    target = span.attributes["rpc.system"]
            else:
                # TODO: Azure specific types
                data.type = "N/A"
        elif span.kind is SpanKind.PRODUCER:  # Messaging
            data.type = "Queue Message"
            # TODO: data.data for messaging
            # TODO: Special logic for data.target for messaging?
        else:  # SpanKind.INTERNAL
            data.type = "InProc"
            data.success = True
        # Apply truncation
        if data.result_code:
            data.result_code = data.result_code[:1024]
        if data.data:
            data.data = data.data[:8192]
        if target:
            data.target = target[:1024]
    for key, val in span.attributes.items():
        # Remove Opentelemetry related span attributes from custom dimensions
        if key.startswith("http.") or \
                key.startswith("db.") or \
                key.startswith("rpc.") or \
                key.startswith("net.") or \
                key.startswith("messaging."):
            continue
        # Apply truncation rules
        # Max key length is 150, value is 8192
        if not key or len(key) > 150 or val is None:
            continue
        data.properties[key] = val[:8192]
    if span.links:
        # Max length for value is 8192
        # Since links are a fixed length (80) in json, max number of links would be 102
        links = []
        for link in span.links:
            if len(links) > 102:
                break
            operation_id = "{:032x}".format(link.context.trace_id)
            span_id = "{:016x}".format(link.context.span_id)
            links.append({"operation_Id": operation_id, "id": span_id})
        data.properties["_MS.links"] = json.dumps(links)
    return envelope
def _convert_span_to_envelope(span: Span) -> TelemetryItem:
    envelope = TelemetryItem(
        name="",
        instrumentation_key="",
        tags=dict(_utils.azure_monitor_context),
        time=ns_to_iso_str(span.start_time),
    )
    if span.resource and span.resource.attributes:
        # TODO: Get Resource attributes from OpenTelemetry SDK when available
        service_name = span.resource.attributes.get("service.name")
        service_namespace = span.resource.attributes.get("service.namespace")
        service_instance_id = span.resource.attributes.get(
            "service.instance.id")
        if service_name:
            if service_namespace:
                envelope.tags["ai.cloud.role"] = service_namespace + \
                    "." + service_name
            else:
                envelope.tags["ai.cloud.role"] = service_name
        if service_instance_id:
            envelope.tags["ai.cloud.roleInstance"] = service_instance_id

    envelope.tags["ai.operation.id"] = "{:032x}".format(span.context.trace_id)
    parent = span.parent
    if parent:
        envelope.tags["ai.operation.parentId"] = "{:016x}".format(
            parent.span_id)
    if span.kind in (SpanKind.CONSUMER, SpanKind.SERVER):
        envelope.name = "Microsoft.ApplicationInsights.Request"
        data = RequestData(
            name=span.name,
            id="{:016x}".format(span.context.span_id),
            duration=_utils.ns_to_duration(span.end_time - span.start_time),
            response_code=str(span.status.status_code.value),
            success=span.status.is_ok,
            properties={},
        )
        envelope.data = MonitorBase(base_data=data, base_type="RequestData")
        if "http.method" in span.attributes:  # HTTP
            if "http.route" in span.attributes:
                envelope.tags["ai.operation.name"] = span.attributes[
                    "http.route"]
            elif "http.path" in span.attributes:
                envelope.tags["ai.operation.name"] = span.attributes[
                    "http.path"]
            else:
                envelope.tags["ai.operation.name"] = span.name

            if "http.url" in span.attributes:
                data.url = span.attributes["http.url"]
                data.properties["request.url"] = span.attributes["http.url"]
            if "http.status_code" in span.attributes:
                status_code = span.attributes["http.status_code"]
                data.response_code = str(status_code)
        elif "messaging.system" in span.attributes:  # Messaging
            envelope.tags["ai.operation.name"] = span.name

            if "messaging.destination" in span.attributes:
                if "net.peer.name" in span.attributes:
                    data.properties["source"] = "{}/{}".format(
                        span.attributes["net.peer.name"],
                        span.attributes["messaging.destination"],
                    )
                elif "net.peer.ip" in span.attributes:
                    data.properties["source"] = "{}/{}".format(
                        span.attributes["net.peer.ip"],
                        span.attributes["messaging.destination"],
                    )
                else:
                    data.properties["source"] = span.attributes[
                        "messaging.destination"]
    else:
        envelope.name = "Microsoft.ApplicationInsights.RemoteDependency"
        data = RemoteDependencyData(
            name=span.name,
            id="{:016x}".format(span.context.span_id),
            result_code=str(span.status.status_code.value),
            duration=_utils.ns_to_duration(span.end_time - span.start_time),
            success=span.status.is_ok,
            properties={},
        )
        envelope.data = MonitorBase(base_data=data,
                                    base_type="RemoteDependencyData")
        if span.kind in (SpanKind.CLIENT, SpanKind.PRODUCER):
            if "http.method" in span.attributes:  # HTTP
                data.type = "HTTP"
                if "net.peer.port" in span.attributes:
                    name = ""
                    if "net.peer.name" in span.attributes:
                        name = span.attributes["net.peer.name"]
                    elif "net.peer.ip" in span.attributes:
                        name = str(span.attributes["net.peer.ip"])
                    data.target = "{}:{}".format(
                        name,
                        str(span.attributes["net.peer.port"]),
                    )
                elif "http.url" in span.attributes:
                    url = span.attributes["http.url"]
                    # data is the url
                    data.data = url
                    parse_url = urlparse(url)
                    # target matches authority (host:port)
                    data.target = parse_url.netloc
                if "http.status_code" in span.attributes:
                    status_code = span.attributes["http.status_code"]
                    data.result_code = str(status_code)
            elif "db.system" in span.attributes:  # Database
                data.type = span.attributes["db.system"]
                # data is the full statement
                if "db.statement" in span.attributes:
                    data.data = span.attributes["db.statement"]
                if "db.name" in span.attributes:
                    data.target = span.attributes["db.name"]
                else:
                    data.target = span.attributes["db.system"]
            elif "rpc.system" in span.attributes:  # Rpc
                data.type = "rpc.system"
                if "rpc.service" in span.attributes:
                    data.target = span.attributes["rpc.service"]
                else:
                    data.target = span.attributes["rpc.system"]
            elif "messaging.system" in span.attributes:  # Messaging
                data.type = "Queue Message | {}" \
                    .format(span.attributes["messaging.system"])
                if "net.peer.ip" in span.attributes and \
                        "messaging.destination" in span.attributes:
                    data.target = "{}/{}".format(
                        span.attributes["net.peer.ip"],
                        span.attributes["messaging.destination"])
                else:
                    data.target = span.attributes["messaging.system"]
            else:
                # TODO: Azure specific types
                data.type = "N/A"
        else:  # SpanKind.INTERNAL
            data.type = "InProc"
            data.success = True
    for key in span.attributes:
        # Remove Opentelemetry related span attributes from custom dimensions
        if key.startswith("http.") or \
                key.startswith("db.") or \
                key.startswith("rpc.") or \
                key.startswith("net.") or \
                key.startswith("messaging."):
            continue
        data.properties[key] = span.attributes[key]
    if span.links:
        links = []
        for link in span.links:
            operation_id = "{:032x}".format(link.context.trace_id)
            span_id = "{:016x}".format(link.context.span_id)
            links.append({"operation_Id": operation_id, "id": span_id})
        data.properties["_MS.links"] = json.dumps(links)
    # TODO: tracestate, tags
    return envelope