This is on .NET 6.
So I've added an enrich callback with the purpose of adding each parameter as a tag:
appBuilder.Services.AddOpenTelemetryTracing((builder) =>
builder
.AddAspNetCoreInstrumentation()
.SetSampler(new AlwaysOnSampler())
.AddSqlClientInstrumentation(options =>
{
options.SetDbStatementForText = true;
options.SetDbStatementForStoredProcedure = true;
options.RecordException = true;
options.EnableConnectionLevelAttributes = true;
options.Enrich = (activity, eventName, rawObject) =>
{
if (eventName.Equals("OnCustom"))
{
activity.SetTag("ParametersAdded", "true");
if (rawObject is SqlCommand cmd)
{
foreach (SqlParameter parameter in cmd.Parameters)
{
activity.SetTag(parameter.ParameterName, parameter.Value.ToString());
}
}
}
};
})
.AddZipkinExporter(options =>
{
options.Endpoint = new Uri(appBuilder.Configuration["TraceExporterUrl"]);
}));
I'm getting the export in Zipkin, but it's not added the tags, and it doesn't seem to be hitting that Enrich callback at all - the ParametersAdded tag isn't being hit either. Can't figure out why this isn't working - Have I fundamentally misunderstood something?
The Enrich is not called for activities that don't have the IsAllDataRequested property set to true.
Related
I'm getting this error every time that the endpoint /actuator/prometheus is being call.
I don't have any idea what could be the problem?
This is the initialization code (I'm sure that openTelemetryEndpoint variable has a value):
builder.Services.AddAllActuators();
builder.Services.AddPrometheusActuator();
// OpenTelemetry configuration
var openTelemetryServiceName = Environment.GetEnvironmentVariable("OTEL_SERVICE_NAME");
var openTelemetryEndpoint = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT");
if (!string.IsNullOrWhiteSpace(openTelemetryEndpoint))
{
// Configure metrics
builder.Services.AddOpenTelemetryMetrics(b =>
{
b.AddHttpClientInstrumentation();
b.AddAspNetCoreInstrumentation();
b.AddMeter(openTelemetryServiceName + "-metrics");
b.AddOtlpExporter(options =>
{
options.Endpoint = new Uri(openTelemetryEndpoint);
options.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
});
});
// Configure tracing
builder.Services.AddOpenTelemetryTracing(b =>
{
b.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(openTelemetryServiceName));
b.AddHttpClientInstrumentation();
b.AddAspNetCoreInstrumentation();
b.AddSource(openTelemetryServiceName + "-activity-source");
b.AddOtlpExporter(options =>
{
options.Endpoint = new Uri(openTelemetryEndpoint);
options.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
});
});
// Configure logging
builder.Logging.AddOpenTelemetry(b =>
{
b.IncludeFormattedMessage = true;
b.IncludeScopes = true;
b.ParseStateValues = true;
b.AddOtlpExporter(options =>
{
options.Endpoint = new Uri(openTelemetryEndpoint);
options.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
});
b.AddConsoleExporter();
});
}
Marcelo,
The error message is saying that you need to use the Steeltoe extension for Metrics: `AddOpenTelemetryMetricsForSteeltoe to get the desired functionality. Steeltoe internally uses OpentelemetryMetrics for its own exports for example /Metrics, /Prometheus and also Wavefront Exporter. If you want to in addition to these add an OLTP exporter you would in addition have to use the extension methods to add the additional configuration.
I want to use Hangfire for background jobs in registration form process,But I am unable to find Startup.cs file code for Hangfire.mongo.
Just an update to this thread,
As of v0.7.11, MongoMigrationOptions have been updated and no longer contains Strategy. As per the release notes, you now have to use MigrationStrategy instead of Strategy. Also, the values you use for these are different as well. See example below.
var migrationOptions = new MongoMigrationOptions
{
MigrationStrategy = new MigrateMongoMigrationStrategy(),
BackupStrategy = new CollectionMongoBackupStrategy()
};
In Startup class
In ConfigureServices method
Add
//you will use some way to get your connection string
var mongoConnection = Configuration.GetConnectionString("MongoDBAtlasJaken");
var migrationOptions = new MongoMigrationOptions
{
Strategy = MongoMigrationStrategy.Drop,
BackupStrategy = MongoBackupStrategy.Collections
};
services.AddHangfire(config =>
{
config.SetDataCompatibilityLevel(CompatibilityLevel.Version_170);
config.UseSimpleAssemblyNameTypeSerializer();
config.UseRecommendedSerializerSettings();
config.UseMongoStorage(mongoConnection, "Hangfire",new MongoStorageOptions { MigrationOptions = migrationOptions });
});
services.AddHangfireServer();
In Configure method you can add if you want
app.UseHangfireDashboard();
#Graeme's anwser works on the older version of Hangfire. For the new version,
The Migration and Backup strategy are changed to class from enum.
var migrationOptions = new MongoMigrationOptions
{
MigrationStrategy = new DropMongoMigrationStrategy(),
BackupStrategy = new CollectionMongoBackupStrategy()
};
The UseMongoStorage method does not accept the collection name anymore.
services.AddHangfire(config =>
{
config.SetDataCompatibilityLevel(CompatibilityLevel.Version_170);
config.UseSimpleAssemblyNameTypeSerializer();
config.UseRecommendedSerializerSettings();
config.UseMongoStorage(mongoConnection, new MongoStorageOptions { MigrationOptions = migrationOptions, CheckConnection = false });
});
services.AddHangfireServer();
I'm trying to understand why the following unit test does not execute the callback. If I modify the code so that the UpdateWorklowInstanceState method only contains 2 parameters (Guid and IList), it works. However, something about having 3 parameters interferes.
What I mean by interferes is that the Callback doesn't appear to get executed. There's no error message. I expect to see the "Error Occurred" message but instead receive an "Element Updated" message which means the Callback did not populate the resultMessages with the NotificationMessage.
public void BusinessObjectReturnsErrorNotification_ReturnErrorMessage()
{
var workflowInstanceGuid = Guid.NewGuid();
var workflowElementModel = new WorkflowElementModel
{
ElementName = "ValidName",
WorkflowInstanceId = workflowInstanceGuid.ToString()
};
var workflowElementInstance = new WorkflowElementInstance
{
ElementName = workflowElementModel.ElementName,
FullDescription = "Full Description",
SummaryDescription = "Summary Description",
RefTime = DateTime.Now,
ElementType = "ElementType"
};
var mockWebApiBusinessObject = new Mock<IWebApiBusinessObject>();
mockWebApiBusinessObject.Setup(m => m.UpdateWorkflowInstanceState(workflowInstanceGuid, workflowElementInstance, It.IsAny<List<NotificationMessage>>()))
.Callback<Guid, WorkflowElementInstance, IList<NotificationMessage>>(
(workflowInstanceId, elementDetails, resultMessages) =>
{
resultMessages.Add(new NotificationMessage("An Error Occured!", MessageSeverity.Error));
});
var controller = new WorkflowElementController(mockWebApiBusinessObject.Object);
var result = controller.UpdateWorkflowElement(workflowElementModel);
Assert.AreEqual("An Error Occured!", result.Content.ReadAsStringAsync().Result);
}
Method under test:
[HttpPost]
[ActionName("UpdateWorkflowElement")]
public HttpResponseMessage UpdateWorkflowElement(WorkflowElementModel workflowElementModel)
{
if (!ModelState.IsValid || workflowElementModel == null)
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
var response = new HttpResponseMessage(HttpStatusCode.OK);
string responseMessage;
if (workflowElementModel.RefTime == DateTime.MinValue)
{
workflowElementModel.RefTime = DateTime.UtcNow;
}
var resultMessages = new List<NotificationMessage>();
var instanceId = new Guid();
if (string.IsNullOrWhiteSpace(workflowElementModel.WorkflowInstanceId) ||
string.IsNullOrWhiteSpace(workflowElementModel.ElementName))
{
responseMessage = "WorkflowInstanceId or ElementName are null or empty";
}
else if (!Guid.TryParse(workflowElementModel.WorkflowInstanceId, out instanceId))
{
responseMessage = "WorkflowInstanceId is not a valid Guid";
}
else
{
var element = new WorkflowElementInstance
{
ElementName = workflowElementModel.ElementName,
RefTime = workflowElementModel.RefTime,
SummaryDescription = workflowElementModel.SummaryDescription ?? "",
FullDescription = workflowElementModel.FullDescription ?? ""
};
_webApiBusinessObject.UpdateWorkflowInstanceState(instanceId, element, resultMessages);
responseMessage = "Element Updated";
}
if (NotificationMessage.HasErrors(resultMessages))
{
responseMessage = resultMessages.Find(m => m.Status == MessageSeverity.Error).Message;
}
response.Content = new StringContent(responseMessage);
return response;
}
It does not work in you case for 3 parameters because you are mixing the expression parameter types.
It.IsAny<List<NotificationMessage>>()
in the setup, as apposed to the
IList<NotificationMessage>
in the callback parameters.
That means the setup expression parameters does not match the callback expression parameters so the call back is not going to be called.
Stick with one type so either go with the List<NotificationMessage> for both
You are also creating new instances of the parameters in the method under test, which would be different instance to the ones used in the setup. That is why the call back is not working. To prove it. Use It.IsAny<>() for all the parameters and it should work
mockWebApiBusinessObject
.Setup(m => m.UpdateWorkflowInstanceState(It.IsAny<Guid>(), It.IsAny<WorkflowElementInstance>(), It.IsAny<List<NotificationMessage>>()))
.Callback<Guid, WorkflowElementInstance, List<NotificationMessage>>(
(workflowInstanceId, elementDetails, resultMessages) =>
{
resultMessages.Add(new NotificationMessage("An Error Occured!", MessageSeverity.Error));
});
Or the more generic interface
mockWebApiBusinessObject
.Setup(m => m.UpdateWorkflowInstanceState(It.IsAny<Guid>(), It.IsAny<WorkflowElementInstance>(), It.IsAny<IList<NotificationMessage>>()))
.Callback<Guid, WorkflowElementInstance, IList<NotificationMessage>>(
(workflowInstanceId, elementDetails, resultMessages) =>
{
resultMessages.Add(new NotificationMessage("An Error Occured!", MessageSeverity.Error));
});
You should also take some time and review Moq Quickstart to get a better understanding of how to use the mocking framework.
Please consider updating at minor places in your unit test.
Add before mocking IWebApiBusinessObject object:
List<NotificationMessage> messages = new List<NotificationMessage>();
Additionally, update Callback :
var mock = new Mock<IWebApiBusinessObject>();
mock.
Setup(m => m.UpdateWorkflowInstanceState(It.IsNotNull<Guid>(), It.IsNotNull<WorkflowElementInstance>(),It.IsAny<List<NotificationMessage>>() )).
Callback(() =>
{
messages.Add(new NotificationMessage("error msg", MessageSeverity.Severe));
messages.Add(new NotificationMessage("Ignore Message", MessageSeverity.Normal)); // this is optional... u can remove it if u want.
});
And need to update the source code method UpdateWorkflowElement(WorkflowElementModel model) to
UpdateWorkflowElement(WorkflowElementModel model, List<NotificationMessage> messages);
Consider changes in unit test code calling UpdateWorkflowElement to
var result = controller.UpdateWorkflowElement(workflowElementModel, messages);
If I have understood your UpdateWorkflowInstanceState() method correctly,
then you are using IWebApiBusinessObject to call UpdateWorkflowInstanceState( , , ) method.
When UpdateWorkflowInstanceState( , , ) executes during unit testing, it fires the Callback in your unit test and adds messages in list of NotificationMessage.
i tried this method that I created but it prompts me an error:
Realms.RealmInvalidObjectException:This object is detached. Was it deleted from the realm?'
public void deleteFromDatabase(List<CashDenomination> denom_list)
{
using (var transaction = Realm.GetInstance(config).BeginWrite())
{
Realm.GetInstance(config).Remove(denom_list[0]);
transaction.Commit();
}
}
what is the proper coding for deleting records from database in realm in C# type of coding?
You are doing it the right way. The error message you are getting indicates that the object was removed already. Are you sure it still exists in the realm?
UPDATE:
I decided to update this answer because my comment on the other answer was a bit hard to read.
Your original code should work fine. However, if you want deleteFromDatabase to accept lists with CashDenomination instances that either have been removed already or perhaps were never added to the realm, you would need to add a check. Furthermore, note that you should hold on to your Realm instance and use it in the transaction you created. In most cases, you want to keep it around even longer, though there is little overhead to obtaining it via GetInstance.
public void deleteFromDatabase(List<CashDenomination> denom_list)
{
if (!denom_list[0].IsValid) // If this object is not in the realm, do nothing.
return;
var realm = Realm.GetInstance(config);
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom_list[0]);
transaction.Commit();
}
}
Now, if you want to use identifiers, you could look it up like you do, but still just use Remove:
public void deleteFromDatabase(int denom_id)
{
var realm = Realm.GetInstance(config);
var denom = realm.All<CashDenomination>().FirstOrDefault(c => c.denom_id == denom_id);
if (denom == null) // If no entry with this id exists, do nothing.
return;
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom);
transaction.Commit();
}
}
Finally, if your CashDenomination has denom_id marked as PrimaryKey, you could look it up like this:
public void deleteFromDatabase(int denom_id)
{
var realm = Realm.GetInstance(config);
var denom = realm.ObjectForPrimaryKey<CashDenomination>(denom_id);
if (denom == null) // If no entry with this id exists, do nothing.
return;
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom);
transaction.Commit();
}
}
public void deleteFromDatabase(Realm realm, long cashDenominatorId)
{
realm.Write(() =>
{
var cashDenominator = realm.All<Person>().Where(c => c.Id == cashDenominatorId);
Realm.RemoveRange<CashDenomination>(((RealmResults<CashDenomination>)cashDenominator));
});
}
Which you would call as
Realm realm = Realm.GetInstance(config);
var denom_list = ...
// ...
deleteFromDatabase(realm, denom_list[0].id);
I already made it having this code :) thanks to #EpicPandaForce 's answer.
public void deleteFromDatabase(int denom_ID, int form_ID)
{
//Realm realm;
//and
//RealmConfiguration config = new RealmConfiguration(dbPath, true);
//was initialized at the top of my class
realm = Realm.GetInstance(config);
realm.Write(() =>
{
var cashflow_denom = realm.All<CashDenomination>().Where(c => c.denom_id == denom_ID);
var cashflow_form = realm.All<CashForm>().Where(c => c.form_id == form_ID);
realm.RemoveRange(((RealmResults<CashDenomination>)cashflow_denom));
realm.RemoveRange(((RealmResults<CashForm>)cashflow_form));
});
}
it is now deleting my data without exception :)
In my WCF service, I am getting the above error with the below code.
I am confused as to why I'm getting this error...
Can someone please explain what I would need to do in order to correct it?
public async Task<List<HH_FuelTkt_Output>> GetFilteredFuelTicketsAsync(HH_FuelTkt_Input value)
{
try
{
using (HandheldEntities DbContext = new HandheldEntities())
{
var tkts = await DbContext.HH_FuelTkt.Select(s =>
new HH_FuelTkt_Output
{
Customer_Name = s.Customer_Name,
FuelTkt_ID = s.FuelTkt_ID,
Image_ID = s.Image_ID,
Ticket_No = s.Ticket_No,
Trans_Timestamp = s.Trans_Timestamp,
Vehicle_No = s.Vehicle_No
}).Where(w => w.Image_ID != null);
The problem is, I forgot to include the ToListAsync on the end of the query.