public void ReportHealth(HealthReport healthReport, HealthReportSendOptions sendOptions) { //_operationLogger.Execute( // $"{ConfigurationValues.ExtensionName}.ServiceFabric.ReportHealth", // () => // { // var operationContext = _operationLogger.Context; // operationContext?.SetProperty("kind", healthReport.Kind.ToString()); // operationContext?.SetProperty("healthState", healthReport.HealthInformation.HealthState.ToString()); // switch (healthReport) // { // case ServiceHealthReport service: // operationContext?.SetProperty("serviceName", service.ServiceName.ToString()); // break; // default: // operationContext?.SetProperty("type", healthReport.GetType().FullName); // break; // } // _healthClientWrapper.ReportHealth(healthReport, sendOptions); // }); Uri serviceName = null; if (healthReport is ServiceHealthReport service) { serviceName = service.ServiceName; } _logger.LogDebug($"Reporting health, kind='{healthReport.Kind}', healthState='{healthReport.HealthInformation.HealthState}', type='{healthReport.GetType().FullName}', serviceName='{serviceName}'"); _healthClientWrapper.ReportHealth(healthReport, sendOptions); }
private void ReportServiceHealth( ServiceFabricDiscoveryOptions options, Uri serviceName, HealthState state, string description = null) { // TODO: this method and the one below have repeated code. Refactor out. var healthReport = new ServiceHealthReport( serviceName: serviceName, healthInformation: new HealthInformation( sourceId: HealthReportSourceId, property: HealthReportProperty, healthState: state) { Description = description, TimeToLive = HealthReportTimeToLive(options), RemoveWhenExpired = true, }); var sendOptions = new HealthReportSendOptions { // Report immediately if unhealthy or if explicitly requested Immediate = options.AlwaysSendImmediateHealthReports ? true : state != HealthState.Ok }; try { _serviceFabricCaller.ReportHealth(healthReport, sendOptions); } catch (Exception ex) // TODO: davidni: not fatal? { Log.ServiceHealthReportFailed(_logger, state, serviceName, ex); } }
/// <summary> /// This is the main entry point for your service replica. /// This method executes when this replica of your service becomes primary and has write status. /// </summary> /// <param name="cancellationToken">Canceled when Service Fabric needs to shut down this service replica.</param> protected override async Task RunAsync(CancellationToken cancellationToken) { VoteDataController controller = new VoteDataController(this.StateManager); HealthReportSendOptions sendOptions = new HealthReportSendOptions() { Immediate = true }; while (true) { cancellationToken.ThrowIfCancellationRequested(); string result = await controller.CheckVotesIntegrity(); if (!String.IsNullOrEmpty(result)) { HealthInformation healthInformation = new HealthInformation("ServiceCode", "StateDictionary", HealthState.Error); healthInformation.Description = result; this.Partition.ReportReplicaHealth(healthInformation, sendOptions); } else { HealthInformation healthInformation = new HealthInformation("ServiceCode", "StateDictionary", HealthState.Ok); this.Partition.ReportReplicaHealth(healthInformation, sendOptions); } await Task.Delay(TimeSpan.FromSeconds(HEALTH_CHECK_INTERVAL_IN_SECONDS), cancellationToken); } }
public void ReportHealth(HealthReport healthReport, HealthReportSendOptions sendOptions) { Uri serviceName = null; if (healthReport is ServiceHealthReport service) { serviceName = service.ServiceName; } Log.ReportHealth(_logger, healthReport.Kind, healthReport.HealthInformation.HealthState, healthReport.GetType().FullName, serviceName); _healthClientWrapper.ReportHealth(healthReport, sendOptions); }
private void ReportReplicaHealth( ServiceFabricDiscoveryOptions options, ServiceWrapper service, Guid partitionId, ReplicaWrapper replica, HealthState state, string description = null) { if (!options.ReportReplicasHealth) { return; } var healthInformation = new HealthInformation( sourceId: HealthReportSourceId, property: HealthReportProperty, healthState: state) { Description = description, TimeToLive = HealthReportTimeToLive(options), RemoveWhenExpired = true, }; HealthReport healthReport; switch (service.ServiceKind) { case ServiceKind.Stateful: healthReport = new StatefulServiceReplicaHealthReport( partitionId: partitionId, replicaId: replica.Id, healthInformation: healthInformation); break; case ServiceKind.Stateless: healthReport = new StatelessServiceInstanceHealthReport( partitionId: partitionId, instanceId: replica.Id, healthInformation: healthInformation); break; default: Log.ReplicaHealthReportFailedInvalidServiceKind(_logger, state, replica.Id, service.ServiceKind); return; } var sendOptions = new HealthReportSendOptions { Immediate = state != HealthState.Ok }; // Report immediately if unhealthy try { _serviceFabricCaller.ReportHealth(healthReport, sendOptions); } catch (Exception ex) // TODO: davidni: not fatal? { Log.ReplicaHealthReportFailed(_logger, state, replica.Id, ex); } }
public void ReportHealth(HealthReport healthReport, HealthReportSendOptions sendOptions) { Uri serviceName = null; if (healthReport is ServiceHealthReport service) { serviceName = service.ServiceName; } _logger.LogDebug($"Reporting health, kind={healthReport.Kind}, healthState={healthReport.HealthInformation.HealthState}, type={healthReport.GetType().FullName}, serviceName={serviceName}"); _healthClientWrapper.ReportHealth(healthReport, sendOptions); }
protected override void ProcessRecord() { HealthReportSendOptions sendOptions = null; if (this.Immediate) { sendOptions = new HealthReportSendOptions() { Immediate = true }; } this.ReportHealth(this.GetHealthReport(this.GetHealthInformation()), sendOptions); }
private void ReportHealth(HealthInformation healthInfo, bool immediate = false) { try { var sendOptions = new HealthReportSendOptions() { Immediate = immediate }; this.partition.ReportPartitionHealth(healthInfo, sendOptions); } catch (Exception e) { // TODO: RDBug 11876054:FabricUS: Handle retryable exceptions for health status publishing Trace.WriteWarning(TraceType, "Exception when reporting health: {0}", e.ToString()); } }
internal void ReportHealth(HealthReport healthReport, HealthReportSendOptions sendOptions, IClusterConnection clusterConnection) { try { /// Warn user if health report will not be sent immediately. this.WarnIfHealthReportBatchingOn(clusterConnection); /// Sending the healthReport received from derived class to cluster-health-manager service. clusterConnection.ReportHealth(healthReport, sendOptions); } catch (Exception anyException) { this.ThrowTerminatingError( anyException, this.SendHealthReportErrorId, clusterConnection); } }
/// <summary> /// Suffix name to be appended with ApplicationName /// </summary> /// <summary> /// Posts a health report against Patch Orchestration Application's NodeAgentService /// </summary> /// <param name="fabricClient">Fabric client object to carry out HM operations</param> /// <param name="applicationName">Name of the application to construct servicename</param> /// <param name="serviceNameSuffix">serviceNameSuffix of the service to construct servicename</param> /// <param name="healthReportProperty">Property of the health report</param> /// <param name="description">Description of the health report</param> /// <param name="healthState">HealthState for the health report</param> /// <param name="timeToLiveInMinutes">Time to live in minutes for health report</param> /// <param name="timeout">Configured timeout for this operation.</param> internal static NodeAgentSfUtilityExitCodes PostServiceHealthReport(FabricClient fabricClient, Uri applicationName, string serviceNameSuffix, string healthReportProperty, string description, HealthState healthState, TimeSpan timeout, long timeToLiveInMinutes = -1) { HealthInformation healthInformation = new HealthInformation(SourceId, healthReportProperty, healthState) { RemoveWhenExpired = true, Description = description }; if (timeToLiveInMinutes >= 0) { healthInformation.TimeToLive = TimeSpan.FromMinutes(timeToLiveInMinutes); } try { ServiceHealthReport healthReport = new ServiceHealthReport(new Uri(applicationName + serviceNameSuffix), healthInformation); HealthReportSendOptions sendOptions = new HealthReportSendOptions(); sendOptions.Immediate = true; fabricClient.HealthManager.ReportHealth(healthReport, sendOptions); Task.Delay(TimeSpan.FromSeconds(2)).GetAwaiter().GetResult(); return(NodeAgentSfUtilityExitCodes.Success); } catch (Exception e) { ServiceEventSource.Current.ErrorMessage( String.Format("HealthManagerHelper.PostNodeHealthReport for Service {0} failed. Exception details {1}", serviceNameSuffix, e)); if (e is FabricTransientException) { return(NodeAgentSfUtilityExitCodes.RetryableException); } else if (e is TimeoutException) { return(NodeAgentSfUtilityExitCodes.TimeoutException); } else { return(NodeAgentSfUtilityExitCodes.Failure); } } }
/// <summary> /// Posts a health report against the Node Agent Service. /// </summary> /// <param name="fabricClient">Fabric client to carry out HealthManager operation on cluster</param> /// <param name="serviceContext">Context of the current service</param> /// <param name="sourceId">SourceId for health report</param> /// <param name="healthReportProperty">Property of the health report</param> /// <param name="description">description of the health report</param> /// <param name="healthState">HealthState for the health report</param> /// <param name="timeToLiveInMinutes">Time to live for health report</param> internal static void PostServiceHealthReport(FabricClient fabricClient, ServiceContext serviceContext, string healthReportProperty, string description, HealthState healthState, long timeToLiveInMinutes = -1) { HealthInformation healthInformation = new HealthInformation(SourceId, healthReportProperty, healthState); healthInformation.RemoveWhenExpired = true; healthInformation.Description = description; if (timeToLiveInMinutes >= 0) { healthInformation.TimeToLive = TimeSpan.FromMinutes(timeToLiveInMinutes); } HealthReportSendOptions sendOptions = new HealthReportSendOptions(); sendOptions.Immediate = true; ServiceHealthReport serviceInstanceHealthReport = new ServiceHealthReport(serviceContext.ServiceName, healthInformation); fabricClient.HealthManager.ReportHealth(serviceInstanceHealthReport, sendOptions); }
public void ReportDeployedServicePackageHealth(HealthInformation healthInfo, HealthReportSendOptions sendOptions) { throw new NotImplementedException(); }
public void ReportDeployedApplicationHealth(HealthInformation healthInfo, HealthReportSendOptions sendOptions) { throw new NotImplementedException(); }
/// <inheritdoc/> public void ReportHealth(HealthReport healthReport, HealthReportSendOptions sendOptions) { _healthClient.ReportHealth(healthReport, sendOptions); }
/// <inheritdoc /> public void ReportReplicaHealth(HealthInformation healthInfo, HealthReportSendOptions sendOptions) { }
/// <inheritdoc/> public void ReportDeployedServicePackageHealth(HealthInformation healthInfo, HealthReportSendOptions sendOptions) { return; }
/// <inheritdoc/> public void ReportDeployedApplicationHealth(HealthInformation healthInfo, HealthReportSendOptions sendOptions) { return; }
public void ReportHealthToServiceFabric(HealthReport healthReport) { if (healthReport == null) { return; } // There is no real need to change Immediate to true here for errors/warnings. This only adds unecessary stress to the // Health subsystem. var sendOptions = new HealthReportSendOptions { Immediate = false }; // Quickly send OK (clears warning/errors states). if (healthReport.State == HealthState.Ok) { sendOptions.Immediate = true; } var timeToLive = TimeSpan.FromMinutes(5); if (healthReport.HealthReportTimeToLive != default) { timeToLive = healthReport.HealthReportTimeToLive; } // Set property for health event. string property = healthReport.Property; if (string.IsNullOrEmpty(property)) { switch (healthReport.Observer) { case ObserverConstants.AppObserverName: property = "ApplicationHealth"; break; case ObserverConstants.CertificateObserverName: property = "SecurityHealth"; break; case ObserverConstants.DiskObserverName: property = "DiskHealth"; break; case ObserverConstants.FabricSystemObserverName: property = "FabricSystemServiceHealth"; break; case ObserverConstants.NetworkObserverName: property = "NetworkHealth"; break; case ObserverConstants.OsObserverName: property = "MachineInformation"; break; case ObserverConstants.NodeObserverName: property = "MachineResourceHealth"; break; default: property = "FOGenericHealth"; break; } } string sourceId = healthReport.Observer; TelemetryData healthData = healthReport.HealthData; if (!string.IsNullOrEmpty(healthReport.Code)) { // Only use FOErrorWarningCode for source sourceId += $"({healthReport.Code})"; } string errWarnPreamble = string.Empty; if (healthReport.State == HealthState.Error || healthReport.State == HealthState.Warning) { errWarnPreamble = $"{healthReport.Observer} detected " + $"{Enum.GetName(typeof(HealthState), healthReport.State)} threshold breach. "; // OSObserver does not monitor resources and therefore does not support related usage threshold configuration. if (healthReport.Observer == ObserverConstants.OsObserverName && property == "OSConfiguration") { errWarnPreamble = $"{ObserverConstants.OsObserverName} detected potential problem with OS configuration: "; property = "OSConfiguration"; } } string message = $"{errWarnPreamble}{healthReport.HealthMessage}"; if (healthData != null) { message = JsonConvert.SerializeObject(healthData); } var healthInformation = new HealthInformation(sourceId, property, healthReport.State) { Description = $"{message}", TimeToLive = timeToLive, RemoveWhenExpired = true, }; // Log event only if ObserverWebApi (REST API Log reader service) app is deployed. if (ObserverManager.ObserverWebAppDeployed && healthReport.EmitLogEvent) { if (healthReport.State == HealthState.Error) { this.logger.LogError(healthReport.NodeName + ": {0}", healthInformation.Description); } else if (healthReport.State == HealthState.Warning) { this.logger.LogWarning(healthReport.NodeName + ": {0}", healthInformation.Description); } else { this.logger.LogInfo(healthReport.NodeName + ": {0}", healthInformation.Description); } } // To SFX. if (healthReport.ReportType == HealthReportType.Application && healthReport.AppName != null) { var appHealthReport = new ApplicationHealthReport(healthReport.AppName, healthInformation); this.fabricClient.HealthManager.ReportHealth(appHealthReport, sendOptions); } else { var nodeHealthReport = new NodeHealthReport(healthReport.NodeName, healthInformation); this.fabricClient.HealthManager.ReportHealth(nodeHealthReport, sendOptions); } }
public void ReportHealthToServiceFabric(Utilities.HealthReport healthReport) { if (healthReport == null) { return; } // There is no real need to change Immediate to true here for errors/warnings. This only adds unecessary stress to the // Health subsystem... var sendOptions = new HealthReportSendOptions { Immediate = false }; // Quickly send OK (clears warning/errors states)... if (healthReport.State == HealthState.Ok) { sendOptions.Immediate = true; } var timeToLive = TimeSpan.FromMinutes(5); if (healthReport.HealthReportTimeToLive != default(TimeSpan)) { timeToLive = healthReport.HealthReportTimeToLive; } string kind = string.Empty; if (healthReport.Code != null) { kind = healthReport.Code + ": "; } string source = healthReport.Observer; string property; // In order for multiple Error/Warning/Ok events to show up in SFX Details view from observer instances, // Event Source Ids must be unique, thus the seemingly strange conditionals inside the cases below: // The apparent duplicity in OR checks is for the case when the incoming report is an OK report, where there is // no error code, but the specific ErrorWarningProperty is known... switch (healthReport.Observer) { case ObserverConstants.AppObserverName: property = "AppHealth"; if (healthReport.Code == ErrorWarningCode.WarningCpuTime || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalCpuTime) { source += "(CPU)"; } else if (healthReport.Code == ErrorWarningCode.WarningMemoryPercentUsed || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalMemoryConsumptionPct) { source += "(Memory%)"; } else if (healthReport.Code == ErrorWarningCode.WarningMemoryCommitted || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalMemoryConsumptionMB) { source += "(MemoryMB)"; } else if (healthReport.Code == ErrorWarningCode.WarningTooManyActiveEphemeralPorts || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalEphemeralPorts) { source += "(ActiveEphemeralPorts)"; } break; case ObserverConstants.CertificateObserverName: property = "SecurityHealth"; break; case ObserverConstants.DiskObserverName: property = "DiskHealth"; if (healthReport.Code == ErrorWarningCode.WarningDiskAverageQueueLength || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.DiskAverageQueueLength) { source += "(DiskQueueLength)"; } else if (healthReport.Code == ErrorWarningCode.WarningDiskSpacePercentUsed || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.DiskSpaceUsagePercentage) { source += "(DiskSpace%)"; } else if (healthReport.Code == ErrorWarningCode.WarningDiskSpaceMB || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.DiskSpaceUsageMB) { source += "(DiskSpaceMB)"; } break; case ObserverConstants.FabricSystemObserverName: property = "FabricSystemServiceHealth"; if (healthReport.Code == ErrorWarningCode.WarningCpuTime || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalCpuTime) { source += "(CPU)"; } else if (healthReport.Code == ErrorWarningCode.WarningMemoryPercentUsed || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalMemoryConsumptionPct) { source += "(Memory%)"; } else if (healthReport.Code == ErrorWarningCode.WarningMemoryCommitted || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalMemoryConsumptionMB) { source += "(MemoryMB)"; } else if (healthReport.Code == ErrorWarningCode.WarningTooManyActiveTcpPorts || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalActivePorts) { source += "(ActivePorts)"; } else if (healthReport.Code == ErrorWarningCode.WarningTooManyActiveEphemeralPorts || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalEphemeralPorts) { source += "(ActiveEphemeralPorts)"; } break; case ObserverConstants.NetworkObserverName: property = "NetworkingHealth"; break; case ObserverConstants.OSObserverName: property = "MachineInformation"; break; case ObserverConstants.NodeObserverName: property = "MachineResourceHealth"; if (healthReport.Code == ErrorWarningCode.WarningCpuTime || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalCpuTime) { source += "(CPU)"; } else if (healthReport.Code == ErrorWarningCode.WarningTooManyFirewallRules || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalActiveFirewallRules) { source += "(FirewallRules)"; } else if (healthReport.Code == ErrorWarningCode.WarningMemoryPercentUsed || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalMemoryConsumptionPct) { source += "(Memory%)"; } else if (healthReport.Code == ErrorWarningCode.WarningMemoryCommitted || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalMemoryConsumptionMB) { source += "(MemoryMB)"; } else if (healthReport.Code == ErrorWarningCode.WarningTooManyActiveTcpPorts || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalActivePorts) { source += "(ActivePorts)"; } else if (healthReport.Code == ErrorWarningCode.WarningTooManyActiveEphemeralPorts || healthReport.ResourceUsageDataProperty == ErrorWarningProperty.TotalEphemeralPorts) { source += "(ActiveEphemeralPorts)"; } break; default: property = "FOGenericHealth"; break; } var healthInformation = new HealthInformation(source, property, healthReport.State) { Description = kind + healthReport.HealthMessage, TimeToLive = timeToLive, RemoveWhenExpired = true, }; // Log event only if ObserverWebApi (REST Log reader...) app is deployed... if (ObserverManager.ObserverWebAppDeployed && healthReport.EmitLogEvent) { if (healthReport.State == HealthState.Error) { this.logger.LogError(healthReport.NodeName + ": {0}", healthInformation.Description); } else if (healthReport.State == HealthState.Warning) { this.logger.LogWarning(healthReport.NodeName + ": {0}", healthInformation.Description); } else { this.logger.LogInfo(healthReport.NodeName + ": {0}", healthInformation.Description); } } // To SFX and Telemetry provider... if (healthReport.ReportType == HealthReportType.Application && healthReport.AppName != null) { var report = new ApplicationHealthReport(healthReport.AppName, healthInformation); this.fabricClient.HealthManager.ReportHealth(report, sendOptions); } else { var report = new NodeHealthReport(healthReport.NodeName, healthInformation); this.fabricClient.HealthManager.ReportHealth(report, sendOptions); } }
public void ReportPartitionHealth( HealthInformation healthInfo, HealthReportSendOptions sendOptions) { }
public void ReportHealthToServiceFabric(HealthReport healthReport) { if (healthReport == null) { return; } // There is no real need to change Immediate to true here for errors/warnings. This only adds unecessary stress to the // Health subsystem. var sendOptions = new HealthReportSendOptions { Immediate = false }; // Quickly send OK (clears warning/errors states). if (healthReport.State == HealthState.Ok) { sendOptions.Immediate = true; } var timeToLive = TimeSpan.FromMinutes(5); if (healthReport.HealthReportTimeToLive != default) { timeToLive = healthReport.HealthReportTimeToLive; } // In order for multiple Error/Warning/Ok events to show up in SFX Details view from observer instances, // Event Source Ids must be unique, thus the seemingly strange conditionals inside the cases below: // The apparent duplicity in OR checks is for the case when the incoming report is an OK report, where there is // no error code, but the specific ErrorWarningProperty is known. string property; switch (healthReport.Observer) { case ObserverConstants.AppObserverName: property = "AppHealth"; break; case ObserverConstants.CertificateObserverName: property = "SecurityHealth"; break; case ObserverConstants.DiskObserverName: property = "DiskHealth"; break; case ObserverConstants.FabricSystemObserverName: property = "FabricSystemServiceHealth"; break; case ObserverConstants.NetworkObserverName: property = "NetworkingHealth"; break; case ObserverConstants.OsObserverName: property = "MachineInformation"; break; case ObserverConstants.NodeObserverName: property = "MachineResourceHealth"; break; default: property = "FOGenericHealth"; break; } string sourceId = healthReport.Observer; if (!string.IsNullOrEmpty(healthReport.Code)) { // Only use FOErrorWarningCode for source sourceId = $"{healthReport.Code}"; } var healthInformation = new HealthInformation(sourceId, property, healthReport.State) { Description = healthReport.HealthMessage, TimeToLive = timeToLive, RemoveWhenExpired = true, }; // Log event only if ObserverWebApi (REST Log reader.) app is deployed. if (ObserverManager.ObserverWebAppDeployed && healthReport.EmitLogEvent) { if (healthReport.State == HealthState.Error) { this.logger.LogError(healthReport.NodeName + ": {0}", healthInformation.Description); } else if (healthReport.State == HealthState.Warning) { this.logger.LogWarning(healthReport.NodeName + ": {0}", healthInformation.Description); } else { this.logger.LogInfo(healthReport.NodeName + ": {0}", healthInformation.Description); } } // To SFX and Telemetry provider. if (healthReport.ReportType == HealthReportType.Application && healthReport.AppName != null) { var appHealthReport = new ApplicationHealthReport(healthReport.AppName, healthInformation); this.fabricClient.HealthManager.ReportHealth(appHealthReport, sendOptions); } else { var nodeHealthReport = new NodeHealthReport(healthReport.NodeName, healthInformation); this.fabricClient.HealthManager.ReportHealth(nodeHealthReport, sendOptions); } }
public void ReportReplicaHealth(HealthInformation healthInfo, HealthReportSendOptions sendOptions) { // Unused throw new NotImplementedException(); }
public void ReportDeployedApplicationHealth(HealthInformation healthInformation, HealthReportSendOptions sendOptions) { HealthInformations?.Add(healthInformation); }
internal void ReportHealth(HealthReport healthReport, HealthReportSendOptions sendOptions) { var clusterConnection = this.GetClusterConnection(); this.ReportHealth(healthReport, sendOptions, clusterConnection); }
public void ReportDeployedServicePackageHealth(HealthInformation healthInformation, HealthReportSendOptions sendOptions) { HealthInformations?.Add(healthInformation); }
public void ReportInstanceHealth( HealthInformation healthInfo, HealthReportSendOptions sendOptions) { }
void ICodePackageActivationContext.ReportApplicationHealth(HealthInformation healthInfo, HealthReportSendOptions sendOptions) { throw new NotImplementedException(); }
void ICodePackageActivationContext.ReportDeployedServicePackageHealth(HealthInformation healthInfo, HealthReportSendOptions sendOptions) { throw new NotImplementedException(); }
public void ReportHealth(HealthReport healthReport, HealthReportSendOptions sendOptions) { throw new NotImplementedException(); }