microsoft / botbuilder-dotnet

Welcome to the Bot Framework SDK for .NET repository, which is the home for the libraries and packages that enable developers to build sophisticated bot applications using .NET.
https://github.com/Microsoft/botframework
MIT License
872 stars 482 forks source link

TelemetryBotIdInitializer does not work for any adapters other than Bot Framework #2477

Closed garypretty closed 5 years ago

garypretty commented 5 years ago

Version

4.5.1

Describe the bug

The TelemetryBotIdInitializer (https://github.com/microsoft/botbuilder-dotnet/blob/7f98f5a2c2cbd17010d71181a39ae3dd7378fb0d/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.WebApi/TelemetryBotIdInitializer.cs) class sets various properties for logging in Application Insights and uses the incoming http request body to define the values, such as conversation Id and user Id.

The problem here is that the initializer is expecting the incoming request JSON to be an Bot Framework Activity, but this will fail for other custom channel adapters, such as WebEx, Twilio or community adapters such as Google / Alexa. This leaves certain key values in the telemetry blank, including activity type and conversation ID.

The crude way I have gotten around this recently when I have been using Google / Alexa adapters along with a traditional Bot Framework adapter is looking for properties on the incoming body and deciding how to parse the request and where to get my conversation / user IDs from (see sample below from my current workaround - but any solution needs to be scalable for multiple existing adapters and capable of being extended for new adapters as they are added, so I am not suggesting this is the route the go down).

This is potentially related to the issue raised by @lauren-mills #2474, which shows the same symptoms.

@darrenj This is the issue I mentioned a few days ago.


 public void Initialize(ITelemetry telemetry)
        {
            if (telemetry == null)
            {
                return;
            }

            var httpContext = _httpContextAccessor.HttpContext;
            var items = httpContext?.Items;

            if (items != null)
            {
                if ((telemetry is RequestTelemetry || telemetry is EventTelemetry || telemetry is TraceTelemetry)
                    && items.ContainsKey(BotActivityKey))
                {
                    if (items[BotActivityKey] is JObject body)
                    {
                        if (body["channelId"] != null)
                        {
                            var channelId = (string) body["channelId"];
                            ParseBotFrameworkRequest(telemetry, body, channelId);
                        }
                        else if (body["conversation"] != null)
                        {
                            var actionPayload = MessageSerializer.Deserialize<Payload>(body.CreateReader());
                            ParseGooglePayload(telemetry, actionPayload);
                        }
                        else if (body["originalDetectIntentRequest"] != null)
                        {
                            var actionRequest = MessageSerializer.Deserialize<GoogleRequestBody>(body.CreateReader());
                            var actionPayload = actionRequest.OriginalDetectIntentRequest.Payload;
                            ParseGooglePayload(telemetry, actionPayload);
                        }
                        else if (body["version"] != null)
                        {
                            var alexaRequest = MessageSerializer.Deserialize<AlexaRequestBody>(body.CreateReader());
                            ParseAlexaRequest(telemetry, alexaRequest);
                        }
                    }
                }
            }
        }

        private void ParseAlexaRequest(ITelemetry telemetry, AlexaRequestBody alexaRequest)
        {
            var userId = alexaRequest.Context.System.User.UserId;
            var conversationId = alexaRequest.Session.SessionId;

            // Set the user id on the Application Insights telemetry item.
            telemetry.Context.User.Id = "alexa" + userId;

            // Set the session id on the Application Insights telemetry item.
            telemetry.Context.Session.Id = conversationId;

            var telemetryProperties = ((ISupportProperties)telemetry).Properties;

            // Set the activity id https://github.com/Microsoft/botframework-obi/blob/master/botframework-activity/botframework-activity.md#id
            if (!telemetryProperties.ContainsKey("activityId"))
            {
                telemetryProperties.Add("activityId", alexaRequest.Request.RequestId);
            }

            // Set the channel id https://github.com/Microsoft/botframework-obi/blob/master/botframework-activity/botframework-activity.md#channel-id
            if (!telemetryProperties.ContainsKey("channelId"))
            {
                telemetryProperties.Add("channelId", "alexa");
            }

            // Set the activity type https://github.com/Microsoft/botframework-obi/blob/master/botframework-activity/botframework-activity.md#type
            if (!telemetryProperties.ContainsKey("activityType"))
            {
                telemetryProperties.Add("activityType",
                    alexaRequest.Request.Type == AlexaRequestTypes.IntentRequest
                        ? ActivityTypes.Message
                        : alexaRequest.Request.Type);
            }
        }

        private void ParseGooglePayload(ITelemetry telemetry, Payload googlePayload)
        {
            var userId = googlePayload.User.UserId;
            var conversationId = googlePayload.Conversation.ConversationId;

            // Set the user id on the Application Insights telemetry item.
            telemetry.Context.User.Id = "google" + (userId ?? conversationId);

            // Set the session id on the Application Insights telemetry item.
            telemetry.Context.Session.Id = conversationId;

            var telemetryProperties = ((ISupportProperties)telemetry).Properties;

            // Set the activity id https://github.com/Microsoft/botframework-obi/blob/master/botframework-activity/botframework-activity.md#id
            var uniqueRequestId = _httpContextAccessor.HttpContext.Items["GoogleUniqueRequestId"]?.ToString();
            if (!telemetryProperties.ContainsKey("activityId") && !string.IsNullOrEmpty(uniqueRequestId))
            {
                telemetryProperties.Add("activityId", uniqueRequestId);
            }

            // Set the channel id https://github.com/Microsoft/botframework-obi/blob/master/botframework-activity/botframework-activity.md#channel-id
            if (!telemetryProperties.ContainsKey("channelId"))
            {
                telemetryProperties.Add("channelId", "google");
            }

            // Set the activity type https://github.com/Microsoft/botframework-obi/blob/master/botframework-activity/botframework-activity.md#type
            if (!telemetryProperties.ContainsKey("activityType"))
            {
                telemetryProperties.Add("activityType", ActivityTypes.Message);
            }
        }

        private void ParseBotFrameworkRequest(ITelemetry telemetry, JObject body, string channelId)
        {
            var userId = string.Empty;
            var from = body["from"];
            if (!string.IsNullOrWhiteSpace(from?.ToString()))
            {
                userId = (string)from["id"];
            }

            var conversationId = string.Empty;
            var conversation = body["conversation"];
            if (!string.IsNullOrWhiteSpace(conversation.ToString()))
            {
                conversationId = (string)conversation["id"];
            }

            // Set the user id on the Application Insights telemetry item.
            telemetry.Context.User.Id = channelId + userId;

            // Set the session id on the Application Insights telemetry item.
            telemetry.Context.Session.Id = conversationId;

            var telemetryProperties = ((ISupportProperties)telemetry).Properties;

            // Set the activity id https://github.com/Microsoft/botframework-obi/blob/master/botframework-activity/botframework-activity.md#id
            if (!telemetryProperties.ContainsKey("activityId"))
            {
                telemetryProperties.Add("activityId", (string)body["id"]);
            }

            // Set the channel id https://github.com/Microsoft/botframework-obi/blob/master/botframework-activity/botframework-activity.md#channel-id
            if (!telemetryProperties.ContainsKey("channelId"))
            {
                telemetryProperties.Add("channelId", (string)channelId);
            }

            // Set the activity type https://github.com/Microsoft/botframework-obi/blob/master/botframework-activity/botframework-activity.md#type
            if (!telemetryProperties.ContainsKey("activityType"))
            {
                telemetryProperties.Add("activityType", (string)body["type"]);
            }
        }
    }

To Reproduce

Steps to reproduce the behavior:

  1. Use a custom adapter such as Google / Alexa community adapters and inspect telemetry logged to Application Insights.

Expected behavior

Properties including conversation ID, user ID and Activity Type should be populated correctly.

[bug]

hcyang commented 5 years ago

@munozemilio, please take a look of this issue. Thanks.

hcyang commented 5 years ago

Hi @munozemilio, please update the issue, thanks.

munozemilio commented 5 years ago

Hi @hcyang, Ill take a look on Monday and asses and ETA for the fix

hcyang commented 5 years ago

Hi @munozemilio, just a reminder that it has been 3 days without labelling it "customer-replied-to."

munozemilio commented 5 years ago

Since there will be some work around the initializers during this release this should be part of that.

garypretty commented 5 years ago

Tracking PR #2580 which should fix this issue.