private async void StartDevices() { // Create namespace manager var namespaceUri = ServiceBusEnvironment.CreateServiceUri("sb", txtNamespace.Text, string.Empty); var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(txtKeyName.Text, txtKeyValue.Text); var namespaceManager = new NamespaceManager(namespaceUri, tokenProvider); // Check if the event hub already exists, if not, create the event hub. if (!await namespaceManager.EventHubExistsAsync(cboEventHub.Text)) { WriteToLog(string.Format(EventHubDoesNotExists, cboEventHub.Text)); return; } var eventHubDescription = await namespaceManager.GetEventHubAsync(cboEventHub.Text); WriteToLog(string.Format(EventHubCreatedOrRetrieved, cboEventHub.Text)); // Check if the SAS authorization rule used by devices to send events to the event hub already exists, if not, create the rule. var authorizationRule = eventHubDescription. Authorization. FirstOrDefault(r => string.Compare(r.KeyName, SenderSharedAccessKey, StringComparison.InvariantCultureIgnoreCase) == 0) as SharedAccessAuthorizationRule; if (authorizationRule == null) { authorizationRule = new SharedAccessAuthorizationRule(SenderSharedAccessKey, SharedAccessAuthorizationRule.GenerateRandomKey(), new[] { AccessRights.Send }); eventHubDescription.Authorization.Add(authorizationRule); await namespaceManager.UpdateEventHubAsync(eventHubDescription); } cancellationTokenSource = new CancellationTokenSource(); var serviceBusNamespace = txtNamespace.Text; var eventHubName = cboEventHub.Text; var senderKey = authorizationRule.PrimaryKey; var status = DefaultStatus; var eventInterval = txtEventIntervalInMilliseconds.IntegerValue; var minValue = txtMinValue.IntegerValue; var maxValue = txtMaxValue.IntegerValue; var minOffset = txtMinOffset.IntegerValue; var maxOffset = txtMaxOffset.IntegerValue; var spikePercentage = trackbarSpikePercentage.Value; var cancellationToken = cancellationTokenSource.Token; // Create one task for each device for (var i = 1; i <= txtDeviceCount.IntegerValue; i++) { var deviceId = i; #pragma warning disable 4014 #pragma warning disable 4014 Task.Run(async () => #pragma warning restore 4014 { var deviceName = $"device{deviceId:000}"; if (radioButtonAmqp.Checked) { // The token has the following format: // SharedAccessSignature sr={URI}&sig={HMAC_SHA256_SIGNATURE}&se={EXPIRATION_TIME}&skn={KEY_NAME} var token = CreateSasTokenForAmqpSender(SenderSharedAccessKey, senderKey, serviceBusNamespace, eventHubName, deviceName, TimeSpan.FromDays(1)); WriteToLog(string.Format(SasToken, deviceId)); var messagingFactory = MessagingFactory.Create(ServiceBusEnvironment.CreateServiceUri("sb", serviceBusNamespace, ""), new MessagingFactorySettings { TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(token), TransportType = TransportType.Amqp }); WriteToLog(string.Format(MessagingFactoryCreated, deviceId)); // Each device uses a different publisher endpoint: [EventHub]/publishers/[PublisherName] var eventHubClient = messagingFactory.CreateEventHubClient($"{eventHubName}/publishers/{deviceName}"); WriteToLog(string.Format(EventHubClientCreated, deviceId, eventHubClient.Path)); while (!cancellationToken.IsCancellationRequested) { // Create random value var value = GetValue(minValue, maxValue, minOffset, maxOffset, spikePercentage); var timestamp = DateTime.Now; // Create EventData object with the payload serialized in JSON format var payload = new Payload { DeviceId = deviceId, Name = deviceName, Status = status, Value = value, Timestamp = timestamp }; var json = JsonConvert.SerializeObject(payload); using (var eventData = new EventData(Encoding.UTF8.GetBytes(json)) { PartitionKey = deviceName }) { // Create custom properties eventData.Properties.Add(DeviceId, deviceId); eventData.Properties.Add(DeviceName, deviceName); eventData.Properties.Add(DeviceStatus, status); eventData.Properties.Add(Value, value); eventData.Properties.Add(Timestamp, timestamp); // Send the event to the event hub await eventHubClient.SendAsync(eventData); WriteToLog($"[Event] DeviceId=[{payload.DeviceId:000}] " + $"Value=[{payload.Value:000}] " + $"Timestamp=[{payload.Timestamp}]"); } // Wait for the event time interval Thread.Sleep(eventInterval); } } else { // The token has the following format: // SharedAccessSignature sr={URI}&sig={HMAC_SHA256_SIGNATURE}&se={EXPIRATION_TIME}&skn={KEY_NAME} var token = CreateSasTokenForHttpsSender(SenderSharedAccessKey, senderKey, serviceBusNamespace, eventHubName, deviceName, TimeSpan.FromDays(1)); WriteToLog(string.Format(SasToken, deviceId)); // Create HttpClient object used to send events to the event hub. var httpClient = new HttpClient { BaseAddress = new Uri(string.Format(EventHubUrl, serviceBusNamespace, eventHubName, deviceName).ToLower()) }; httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", token); httpClient.DefaultRequestHeaders.Add("ContentType", "application/json;type=entry;charset=utf-8"); WriteToLog(string.Format(HttpClientCreated, deviceId, httpClient.BaseAddress)); while (!cancellationToken.IsCancellationRequested) { // Create random value var value = GetValue(minValue, maxValue, minOffset, maxOffset, spikePercentage); var timestamp = DateTime.Now; // Create EventData object with the payload serialized in JSON format var payload = new Payload { DeviceId = deviceId, Name = deviceName, Status = status, Value = value, Timestamp = timestamp }; var json = JsonConvert.SerializeObject(payload); // Create HttpContent var postContent = new ByteArrayContent(Encoding.UTF8.GetBytes(json)); // Create custom properties postContent.Headers.Add(DeviceId, deviceId.ToString(CultureInfo.InvariantCulture)); postContent.Headers.Add(DeviceName, deviceName); //postContent.Headers.Add(DeviceStatus, location); postContent.Headers.Add(Value, value.ToString(CultureInfo.InvariantCulture)); postContent.Headers.Add(Timestamp, timestamp.ToString(CultureInfo.InvariantCulture)); try { var response = await httpClient.PostAsync( httpClient.BaseAddress + "/messages" + "?timeout=60" + ApiVersion, postContent, cancellationToken); response.EnsureSuccessStatusCode(); WriteToLog($"[Event] DeviceId=[{payload.DeviceId:000}] " + $"Value=[{payload.Value:000}] " + $"Timestamp=[{payload.Timestamp}]"); } catch (HttpRequestException ex) { WriteToLog(string.Format(SendFailed, deviceId, ex.Message)); } // Wait for the event time interval Thread.Sleep(eventInterval); } } }, cancellationToken).ContinueWith(t => #pragma warning restore 4014 #pragma warning restore 4014 { if (t.IsFaulted && t.Exception != null) { HandleException(t.Exception); } }, cancellationToken); } }
public async Task ProcessEventAsync(Payload payload) { try { // Validate payload if (payload == null) { return; } // Enqueue the new payload var queueResult = await StateManager.TryGetStateAsync<Queue<Payload>>(QueueState); if (queueResult.HasValue) { var queue = queueResult.Value; queue.Enqueue(payload); // The actor keeps the latest n payloads in a queue, where n is // defined by the QueueLength parameter in the Settings.xml file. if (queue.Count > ((DeviceActorService)ActorService).QueueLength) { queue.Dequeue(); } } // Retrieve Metadata from the Actor state var metadataResult = await StateManager.TryGetStateAsync<Device>(MetadataState); var metadata = metadataResult.HasValue ? metadataResult.Value : new Device { DeviceId = payload.DeviceId, Name = payload.Name, MinThreshold = MinThresholdDefault, MaxThreshold = MaxThresholdDefault, Model = Unknown, Type = Unknown, Manufacturer = Unknown, City = Unknown, Country = Unknown }; // Trace ETW event ActorEventSource.Current.Message($"Id=[{payload.DeviceId}] Value=[{payload.Value}] Timestamp=[{payload.Timestamp}]"); // This ETW event is traced to a separate table with respect to the message ActorEventSource.Current.Telemetry(metadata, payload); // Track Application Insights event Program.TelemetryClient.TrackEvent(new EventTelemetry { Name = "Telemetry", Properties = { {"DeviceId", metadata.DeviceId.ToString(CultureInfo.InvariantCulture)}, {"Name", metadata.Name}, {"City", metadata.City}, {"Country", metadata.Country}, {"Manufacturer", metadata.Manufacturer}, {"Model", metadata.Model}, {"Type", metadata.Type}, {"MinThreshold", metadata.MinThreshold.ToString(CultureInfo.InvariantCulture)}, {"MaxThreshold", metadata.MaxThreshold.ToString(CultureInfo.InvariantCulture)}, {"Value", payload.Value.ToString(CultureInfo.InvariantCulture)}, {"Status", payload.Status}, {"Timestamp", payload.Timestamp.ToString(CultureInfo.InvariantCulture)}, {"ActorType", "DeviceActor"}, {"ActorId", Id.ToString()}, {"ServiceName", ActorService.Context.ServiceName.ToString()}, {"Partition", ActorService.Context.PartitionId.ToString()}, {"Node", ActorService.Context.NodeContext.NodeName} }, Metrics = { {"TelemetryValue", payload.Value}, {"TelemetryCount", 1} }, }); // Real spikes happen when both Spike1 and Spike2 are equal to 1. By the way, you can change the logic if (payload.Value < metadata.MinThreshold || payload.Value > metadata.MaxThreshold) { // Create EventData object with the payload serialized in JSON format var alert = new Alert { DeviceId = metadata.DeviceId, Name = metadata.Name, MinThreshold = metadata.MinThreshold, MaxThreshold = metadata.MaxThreshold, Model = metadata.Model, Type = metadata.Type, Manufacturer = metadata.Manufacturer, City = metadata.City, Country = metadata.Country, Status = payload.Status, Value = payload.Value, Timestamp = payload.Timestamp }; var json = JsonConvert.SerializeObject(alert); using (var eventData = new EventData(Encoding.UTF8.GetBytes(json)) { PartitionKey = payload.Name }) { // Create custom properties eventData.Properties.Add(DeviceId, payload.DeviceId); eventData.Properties.Add(Value, payload.Value); eventData.Properties.Add(Timestamp, payload.Timestamp); // Send the event to the event hub await eventHubClient.SendAsync(eventData); // Trace ETW event ActorEventSource.Current.Message($"[Alert] Id=[{payload.DeviceId}] Value=[{payload.Value}] Timestamp=[{payload.Timestamp}]"); // This ETW event is traced to a separate table ActorEventSource.Current.Alert(metadata, payload); // Track Application Insights event Program.TelemetryClient.TrackEvent(new EventTelemetry { Name = "Alert", Properties = { {"DeviceId", metadata.DeviceId.ToString(CultureInfo.InvariantCulture)}, {"Name", metadata.Name}, {"City", metadata.City}, {"Country", metadata.Country}, {"Manufacturer", metadata.Manufacturer}, {"Model", metadata.Model}, {"Type", metadata.Type}, {"MinThreshold", metadata.MinThreshold.ToString(CultureInfo.InvariantCulture)}, {"MaxThreshold", metadata.MaxThreshold.ToString(CultureInfo.InvariantCulture)}, {"Value", payload.Value.ToString(CultureInfo.InvariantCulture)}, {"Status", payload.Status}, {"Timestamp", payload.Timestamp.ToString(CultureInfo.InvariantCulture)}, {"ActorType", "DeviceActor"}, {"ActorId", Id.ToString()}, {"ServiceName", ActorService.Context.ServiceName.ToString()}, {"Partition", ActorService.Context.PartitionId.ToString()}, {"Node", ActorService.Context.NodeContext.NodeName} }, Metrics = { {"AlertValue", payload.Value}, {"AlertCount", 1} }, }); } } } catch (Exception ex) { // Trace exception as ETW event ActorEventSource.Current.Error(ex); // Trace exception using Application Insights Program.TelemetryClient.TrackException(ex, new Dictionary<string, string> { { "ActorType", "DeviceActor"}, { "ActorId", Id.ToString()}, { "ServiceName", ActorService.Context.ServiceName.ToString()}, { "Partition", ActorService.Context.PartitionId.ToString()}, { "Node", ActorService.Context.NodeContext.NodeName} }); } }
public void Alert(Device device, Payload payload) { if (device != null && payload != null && IsEnabled()) { Alert(device.DeviceId, device.Name, device.City, device.Country, device.Manufacturer, device.Model, device.Type, device.MinThreshold, device.MaxThreshold, payload.Value, payload.Status, payload.Timestamp); } }