internal async Task OnBeforeCall(string id, CancellationToken cancellationToken, GetEventData getEventData, SignalDelegate signal, string processRecordId) { var data = EventDataConverter.ConvertFrom(getEventData()); // also, we manually use our TypeConverter to return an appropriate type var request = data?.RequestMessage as HttpRequestMessage; if (request != null) { AzurePSQoSEvent qos; IEnumerable <string> headerValues; if (_telemetry.TryGetValue(processRecordId, out qos)) { foreach (var headerName in ClientHeaders) { if (request.Headers.TryGetValues(headerName, out headerValues) && headerValues.Any()) { qos.ClientRequestId = headerValues.First(); break; } } } /// Print formatted request message await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent(GeneralUtilities.GetLog(request))); } }
internal async Task OnResponseCreated(string id, CancellationToken cancellationToken, GetEventData getEventData, SignalDelegate signal, string processRecordId) { var data = EventDataConverter.ConvertFrom(getEventData()); var response = data?.ResponseMessage as HttpResponseMessage; if (response != null) { AzurePSQoSEvent qos; if (_telemetry.TryGetValue(processRecordId, out qos) && null != response?.Headers) { IEnumerable <string> headerValues; foreach (var headerName in ClientHeaders) { if (response.Headers.TryGetValues(headerName, out headerValues) && headerValues.Any()) { qos.ClientRequestId = headerValues.First(); break; } } } /// Print formatted response message await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent(GeneralUtilities.GetLog(response))); } }
internal async Task OnFinally(string id, CancellationToken cancellationToken, GetEventData getEventData, SignalDelegate signal, string processRecordId) { var data = EventDataConverter.ConvertFrom(getEventData()); if (data?.ResponseMessage is HttpResponseMessage response) { AzurePSQoSEvent qos; if (_telemetry.TryGetValue(processRecordId, out qos)) { if (!response.IsSuccessStatusCode && qos.Exception == null) { // add "InternalException" as message because it is just for telemtry tracking. AzPSCloudException ex = (response.StatusCode == HttpStatusCode.NotFound) ? new AzPSResourceNotFoundCloudException("InternalException") : new AzPSCloudException("InternalException"); try { string responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); CloudError cloudError = SafeJsonConvert.DeserializeObject <CloudError>(responseContent, DeserializationSettings); ex.Body = cloudError; ex.Data[AzurePSErrorDataKeys.CloudErrorCodeKey] = cloudError.Code; } catch (Exception exception) { await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent($"[{id}]: Cannot deserialize due to {exception.Message}")); } qos.Exception = ex; await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent($"[{id}]: Getting exception '{qos.Exception}' from response")); } } } }
internal async Task OnPolling(string id, CancellationToken cancellationToken, GetEventData getEventData, SignalDelegate signal, string processRecordId) { var data = EventDataConverter.ConvertFrom(getEventData()); // a polling event contains a response, and the response contains the request // so we can print them both in one event if (data?.RequestMessage is HttpRequestMessage request) { try { // Print formatted request message await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent(GeneralUtilities.GetLog(request))); } catch { // request was disposed, ignore } } if (data?.ResponseMessage is HttpResponseMessage response) { try { // Print formatted response message await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent(GeneralUtilities.GetLog(response))); } catch { // response was disposed, ignore } } }
/// <summary> /// The cmdlet will call this for every event during the pipeline. /// </summary> /// <param name="id">a <c>string</c> containing the name of the event being raised (well-known events are in <see cref="Microsoft.Azure.Commands.Common.Events"/></param> /// <param name="cancellationToken">a <c>CancellationToken</c> indicating if this request is being cancelled.</param> /// <param name="getEventData">a delegate to call to get the event data for this event</param> /// <param name="signal">a delegate to signal an event from the handler to the cmdlet.</param> /// <param name="invocationInfo">The <see cref="System.Management.Automation.InvocationInfo" /> from the cmdlet</param> /// <param name="parameterSetName">The <see cref="string" /> containing the name of the parameter set for this invocation (if available></param> /// <param name="correlationId">The <see cref="string" /> containing the correlation id for the cmdlet (if available)</param> /// <param name="processRecordId">The <see cref="string" /> containing the correlation id for the individual process record. (if available)</param> /// <param name="exception">The <see cref="System.Exception" /> that is being thrown (if available)</param> public async Task EventListener(string id, CancellationToken cancellationToken, GetEventData getEventData, SignalDelegate signal, System.Management.Automation.InvocationInfo invocationInfo, string parameterSetName, string correlationId, string processRecordId, System.Exception exception) { switch (id) { case Events.CmdletException: { var data = EventDataConverter.ConvertFrom(getEventData()); await signal("Warning", cancellationToken, () => EventHelper.CreateLogEvent($"Received Exception with message '{data?.Message}'")); } break; case Events.BeforeCall: { var data = EventDataConverter.ConvertFrom(getEventData()); // also, we manually use our TypeConverter to return an appropriate type await signal("Debug", cancellationToken, () => EventHelper.CreateLogEvent($"BEFORE CALL The contents are '{data?.Id}' and '{data?.Message}'")); var request = data?.RequestMessage as HttpRequestMessage; if (request != null) { // alias/casting the request message to an HttpRequestMessage is necessary so that we can // support other protocols later on. (ie, JSONRPC, MQTT, GRPC ,AMPQ, Etc..) // at this point, we can do with the request request.Headers.Add("x-ms-peekaboo", "true"); await signal("Debug", cancellationToken, () => EventHelper.CreateLogEvent(GeneralUtilities.GetLog(request))); } } break; case Events.ResponseCreated: { // once we're sure we're handling the event, then we can retrieve the event data. // (this ensures that we're not doing any of the work unless we really care about the event. ) var data = EventDataConverter.ConvertFrom(getEventData()); await signal("Debug", cancellationToken, () => EventHelper.CreateLogEvent($"RESPONSE CREATED The contents are '{data?.Id}' and '{data?.Message}'")); var response = data?.ResponseMessage as HttpResponseMessage; if (response != null) { await signal("Debug", cancellationToken, () => EventHelper.CreateLogEvent(GeneralUtilities.GetLog(response))); } } break; default: // By default, just print out event details getEventData.Print(signal, cancellationToken, "Verbose", id); break; } }
internal async Task OnCmdletException(string id, CancellationToken cancellationToken, GetEventData getEventData, SignalDelegate signal, string processRecordId, Exception exception) { var data = EventDataConverter.ConvertFrom(getEventData()); await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent($"[{id}]: Received Exception with message '{data?.Message}'")); AzurePSQoSEvent qos; if (_telemetry.TryGetValue(processRecordId, out qos)) { qos.Exception = exception; } }
/// <summary> /// Print event details to the provided stream /// </summary> /// <param name="getEventData">The event data to print</param> /// <param name="signal">The delegate for signaling events to the runtime</param> /// <param name="token">The cancellation token for the request</param> /// <param name="streamName">The name of the stream to print data to</param> /// <param name="eventName">The name of the event to be printed</param> public static async void Print(this GetEventData getEventData, SignalDelegate signal, CancellationToken token, string streamName, string eventName) { var eventDisplayName = SplitPascalCase(eventName).ToUpperInvariant(); var data = EventDataConverter.ConvertFrom(getEventData()); // also, we manually use our TypeConverter to return an appropriate type if (data.Id != "Verbose" && data.Id != "Warning" && data.Id != "Debug" && data.Id != "Information" && data.Id != "Error") { await signal(streamName, token, () => EventHelper.CreateLogEvent($"{eventDisplayName} The contents are '{data?.Id}' and '{data?.Message}'")); if (data != null) { await signal(streamName, token, () => EventHelper.CreateLogEvent($"{eventDisplayName} Parameter: '{data.Parameter}'\n{eventDisplayName} RequestMessage '{data.RequestMessage}'\n{eventDisplayName} Response: '{data.ResponseMessage}'\n{eventDisplayName} Value: '{data.Value}'")); await signal(streamName, token, () => EventHelper.CreateLogEvent($"{eventDisplayName} ExtendedData Type: '{data.ExtendedData?.GetType()}'\n{eventDisplayName} ExtendedData '{data.ExtendedData}'")); } } }
internal async Task OnCmdletException(string id, CancellationToken cancellationToken, GetEventData getEventData, SignalDelegate signal, string processRecordId, Exception exception) { var data = EventDataConverter.ConvertFrom(getEventData()); await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent($"[{id}]: Received Exception with message '{data?.Message}'")); AzurePSQoSEvent qos; if (_telemetry.TryGetValue(processRecordId, out qos)) { await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent($"[{id}]: Sending new QosEvent for command '{qos.CommandName}': {qos.ToString()}")); qos.IsSuccess = false; qos.Exception = exception; _telemetry.LogEvent(processRecordId); } }
internal async Task OnFinally(string id, CancellationToken cancellationToken, GetEventData getEventData, SignalDelegate signal, string processRecordId) { var data = EventDataConverter.ConvertFrom(getEventData()); if (data?.ResponseMessage is HttpResponseMessage response) { AzurePSQoSEvent qos; if (_telemetry.TryGetValue(processRecordId, out qos)) { if (!response.IsSuccessStatusCode && qos.Exception == null) { AzPSCloudException ex = (response.StatusCode == HttpStatusCode.NotFound) ? new AzPSResourceNotFoundCloudException(String.Empty) : new AzPSCloudException(String.Empty); ex.Response = new HttpResponseMessageWrapper(response, String.Empty); qos.Exception = ex; await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent($"[{id}]: Getting exception '{qos.Exception}' from response")); } } } }
/// <summary> /// The cmdlet will call this for every event during the pipeline. /// </summary> /// <param name="id">a <c>string</c> containing the name of the event being raised (well-known events are in <see cref="Microsoft.Azure.Commands.Common.Events"/></param> /// <param name="cancellationToken">a <c>CancellationToken</c> indicating if this request is being cancelled.</param> /// <param name="getEventData">a delegate to call to get the event data for this event</param> /// <param name="signal">a delegate to signal an event from the handler to the cmdlet.</param> /// <param name="invocationInfo">The <see cref="System.Management.Automation.InvocationInfo" /> from the cmdlet</param> /// <param name="parameterSetName">The <see cref="string" /> containing the name of the parameter set for this invocation (if available></param> /// <param name="correlationId">The <see cref="string" /> containing the correlation id for the cmdlet (if available)</param> /// <param name="processRecordId">The <see cref="string" /> containing the correlation id for the individual process record. (if available)</param> /// <param name="exception">The <see cref="System.Exception" /> that is being thrown (if available)</param> public async Task EventListener(string id, CancellationToken cancellationToken, GetEventData getEventData, SignalDelegate signal, InvocationInfo invocationInfo, string parameterSetName, string correlationId, string processRecordId, System.Exception exception) { /// Drain the queue of ADAL events whenever an event is fired DrainMessages(signal, cancellationToken); switch (id) { case Events.BeforeCall: { var data = EventDataConverter.ConvertFrom(getEventData()); // also, we manually use our TypeConverter to return an appropriate type var request = data?.RequestMessage as HttpRequestMessage; if (request != null) { AzurePSQoSEvent qos; if (_telemetryEvents.TryGetValue(processRecordId, out qos)) { IEnumerable <string> headers; if (request.Headers != null && request.Headers.TryGetValues("x-ms-client-request-id", out headers)) { qos.ClientRequestId = headers.FirstOrDefault(); await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent($"[{id}]: Amending QosEvent for command '{qos.CommandName}': {qos.ToString()}")); } } /// Print formatted request message await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent(GeneralUtilities.GetLog(request))); } } break; case Events.CmdletProcessRecordAsyncStart: { var qos = CreateQosEvent(invocationInfo, parameterSetName, correlationId); await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent($"[{id}]: Created new QosEvent for command '{qos.CommandName}': {qos.ToString()}")); _telemetryEvents.Add(processRecordId, qos); } break; case Events.CmdletProcessRecordAsyncEnd: { AzurePSQoSEvent qos; if (_telemetryEvents.TryGetValue(processRecordId, out qos)) { qos.IsSuccess = qos.Exception == null; await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent($"[{id}]: Sending new QosEvent for command '{qos.CommandName}': {qos.ToString()}")); _metricHelper.LogEvent(qos); _telemetryEvents.Remove(processRecordId); } } break; case Events.CmdletException: { var data = EventDataConverter.ConvertFrom(getEventData()); await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent($"[{id}]: Received Exception with message '{data?.Message}'")); AzurePSQoSEvent qos; if (_telemetryEvents.TryGetValue(processRecordId, out qos)) { await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent($"[{id}]: Sending new QosEvent for command '{qos.CommandName}': {qos.ToString()}")); qos.IsSuccess = false; qos.Exception = exception; _metricHelper.LogEvent(qos); _telemetryEvents.Remove(processRecordId); } } break; case Events.ResponseCreated: { var data = EventDataConverter.ConvertFrom(getEventData()); var response = data?.ResponseMessage as HttpResponseMessage; if (response != null) { AzurePSQoSEvent qos; if (_telemetryEvents.TryGetValue(processRecordId, out qos)) { qos.ClientRequestId = response?.Headers?.GetValues("x-ms-request-id").FirstOrDefault(); } /// Print formatted response message await signal(Events.Debug, cancellationToken, () => EventHelper.CreateLogEvent(GeneralUtilities.GetLog(response))); } } break; default: getEventData.Print(signal, cancellationToken, Events.Information, id); break; } }