Note: You can't log from a standalone console application, such as the application presented in
This page contains the following information:
Before using logging in a custom application, make sure logging is enabled in Relativity to write to an appropriate sink. If you want to use the defaults, make sure the default configuration row in the RelativityLogging.Configuration table is set to True (1). This enables logging to the EDDSLogging.RelativityLogs table at the Error (4) level. .
The IAPILog interface included in the Relativity API namespace enables logging functionality. These IAPILog interface methods correspond to the available logging levels:
public interface IAPILog { void LogVerbose(string messageTemplate, params object[] propertyValues); void LogDebug(string messageTemplate, params object[] propertyValues); void LogInformation(string messageTemplate, params object[] propertyValues); void LogWarning(string messageTemplate, params object[] propertyValues); void LogError(string messageTemplate, params object[] propertyValues); void LogFatal(string messageTemplate, params object[] propertyValues); ... }
When called from the code, the methods logs the events at the specified level and higher when the events occur. For example, the following code logs Debug, Information, Warning, Error, and Fatal-level events. The events may occur when cleaning Kepler Service Host temporary directories.
Logger.LogDebug("Cleaning up any left over files and folders in the Kepler Service Host temporary directories");
Each method can also take an exception object. This outputs the exception and stack trace into a separate field in the database to assist with searching.
public interface IAPILog { ... void LogVerbose(Exception exception, string messageTemplate, params object[] propertyValues); void LogDebug(Exception exception, string messageTemplate, params object[] propertyValues); void LogInformation(Exception exception, string messageTemplate, params object[] propertyValues); void LogWarning(Exception exception, string messageTemplate, params object[] propertyValues); void LogError(Exception exception, string messageTemplate, params object[] propertyValues); void LogFatal(Exception exception, string messageTemplate, params object[] propertyValues); ... }
The following are examples of logging from an agent, a custom page, and an event handler from the
[kCura.Agent.CustomAttributes.Name("Patient Notes Processing Agent")] [System.Runtime.InteropServices.Guid("3dc132a6-ba0f-448a-bc10-1667fa04b7cd")] public class PatientNotesProcessingAgent : kCura.Agent.AgentBase { private Relativity.API.IAPILog _logger; public static readonly String[] SYMPTOMS_TO_FIND = new String[] { "bumps", "fever", "lethargic", "fatigued", "rash", "cough", "headache" }; public static readonly Guid PATIENT_NOTES_FIELD_GUID = new Guid("5702F31B-48AC-4E2A-9000-A48B3E3ABDBF"); public static readonly Guid REQUIRES_FURTHER_EVALUATION_FIELD_GUID = new Guid("4B247F25-966D-4BFB-AD6F-2647D93B7DA4"); public static readonly Guid PATIENT_RDO_GUID = new Guid("EDC3AF33-7D25-4897-8285-6E36EA1D4AAE"); private static Int32 ErrorCount { get; set; } public override void Execute() { //Get the logger from the helper and set the ForContext to this class. _logger = this.Helper.GetLoggerFactory().GetLogger().ForContext<PatientNotesProcessingAgent>(); //Add a ForContext property called MethodName to a new logger used by this method. //This new logger will have the ForContext from the private _logger variable. Relativity.API.IAPILog methodLogger = _logger.ForContext("MethodName", "Execute", false); //Log a message. methodLogger.LogVerbose("Starting Execution of PatientNotesProcessingAgent"); PatientJobDTO patientToProcessJobDTO = null; Int32 keySymptomsFound; //Get the current Agent artifactID Int32 agentArtifactID = this.AgentID; //Get the EDDS database context Relativity.API.IDBContext eddsDBContext = this.Helper.GetDBContext(-1); try { //Get the next available job from the queue this.RaiseMessage("Looking for the next job in the queue", 10); //Other Agent work … } } }
Note: This code sample also demonstrates the use of the RaiseMessage() method of the AgentBase to log information-level events.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace PatientTracker.CustomPages.Controllers { /// <summary> /// This custom page shows how to use a patient artifactID and current workspace artifactID to retrieve information from the RSAPI, and then display a profile page for the patient. /// </summary> public class PatientController : Controller { private Relativity.API.IAPILog _logger; public static readonly Guid PATIENT_RDO_GUID = new Guid("EDC3AF33-7D25-4897-8285-6E36EA1D4AAE"); public static readonly Guid FIRST_NAME_FIELD_GUID = new Guid("EB024552-3A1B-40C1-B4DC-5815C3DD3AD3"); public static readonly Guid LAST_NAME_FIELD_GUID = new Guid("DA73E11E-9D02-4D29-9D3C-F84E66223B2A"); public static readonly Guid GENDER_FIELD_GUID = new Guid("04E5F293-A4E1-4DF4-8816-F1E6645AE001"); public static readonly Guid DATE_OF_BIRTH_FIELD_GUID = new Guid("96BC22AF-F2F6-4C92-AD96-CF08BF9AAB4D"); public static readonly Guid PATIENT_NOTES_FIELD_GUID = new Guid("5702F31B-48AC-4E2A-9000-A48B3E3ABDBF"); public static readonly Guid PICTURE_FIELD_GUID = new Guid("006F21C0-66C8-46E0-94B2-EF37C6478C2D"); public ActionResult Index(Int32 patientArtifactID, Int32 workspaceArtifactID) { //Get the logger from the helper and set the ForContext to this class. _logger = Relativity.CustomPages.ConnectionHelper.Helper().GetLoggerFactory().GetLogger().ForContext<HomeController>(); PatientTracker.CustomPages.Models.PatientModel patient = new Models.PatientModel(); kCura.Relativity.Client.DTOs.RDO patientRDO = null; try { //Create an instance of the RSAPIClient so we can pull back information about the patient. using (kCura.Relativity.Client.IRSAPIClient client = Relativity.CustomPages.ConnectionHelper.Helper().GetServicesManager().CreateProxy<kCura.Relativity.Client.IRSAPIClient>(Relativity.API.ExecutionIdentity.System)) { _logger.LogInformation("Attempting to pull patient info for {PatientArtifactID} in workspace {WorkspaceID}", patientArtifactID, workspaceArtifactID); //Set the workspace artifactID. client.APIOptions.WorkspaceID = workspaceArtifactID; //Create an instance of the RDO with the Patient RDO GUID and the patient artifactID. patientRDO = new kCura.Relativity.Client.DTOs.RDO(patientArtifactID); patientRDO.ArtifactTypeGuids.Add(PATIENT_RDO_GUID); patientRDO.Fields = kCura.Relativity.Client.DTOs.FieldValue.AllFields; //Get the patient RDO from the RSAPI. patientRDO = client.Repositories.RDO.Read(patientRDO).Results[0].Artifact; //Set properties on the patient model. patient.FirstName = patientRDO.Fields.Where(x => x.Guids.Contains(FIRST_NAME_FIELD_GUID)).Single().ValueAsFixedLengthText; patient.LastName = patientRDO.Fields.Where(x => x.Guids.Contains(LAST_NAME_FIELD_GUID)).Single().ValueAsFixedLengthText; patient.DateOfBirth = patientRDO.Fields.Where(x => x.Guids.Contains(DATE_OF_BIRTH_FIELD_GUID)).Single().ValueAsDate.Value; patient.PatientNotes = patientRDO.Fields.Where(x => x.Guids.Contains(PATIENT_NOTES_FIELD_GUID)).Single().ValueAsLongText; //Construct a download request used to get a proper download url for the file to be downloaded. kCura.Relativity.Client.DownloadURLRequest pictureFieldDownloadRequest = new kCura.Relativity.Client.DownloadURLRequest(client.APIOptions); Uri currentUrl = Request.Url; pictureFieldDownloadRequest.BaseURI = new Uri(String.Format("{0}://{1}/", currentUrl.Scheme, currentUrl.Host)); pictureFieldDownloadRequest.Target.FieldGuid = PICTURE_FIELD_GUID; pictureFieldDownloadRequest.Target.ObjectArtifactId = patientArtifactID; //Set the picture file path on the patient model. patient.PicturePath = client.Repositories.RDO.GetFileFieldDownloadURL(pictureFieldDownloadRequest).URL; } } catch (System.Exception ex) { patient.PatientNotes = "EXCEPTION: " + ex.ToString(); //Log an error. _logger.LogError(ex, "There was an issue pulling back patient info."); } return View(patient); } } }
namespace PatientTracker.EventHandlers { /// <summary> /// This event handler will execute before the page loads and will populate the Co-Pay field with a default value /// </summary> [kCura.EventHandler.CustomAttributes.Description("Patient pre-load event handler")] [System.Runtime.InteropServices.Guid("CB6ED881-F432-4F9A-8187-B87B1FA89D50")] class PatientPreLoadEventHandler : kCura.EventHandler.PreLoadEventHandler { Relativity.API.IAPILog _logger; private const Decimal DEFAULT_CO_PAY = 25.0M; public static readonly Guid CO_PAY_FIELD_GUID = new Guid("24402D3C-4EAF-4C33-B244-A145EEB7C6C1"); public override kCura.EventHandler.Response Execute() { //Get the logger from the helper and set the ForContext to this class. _logger = this.Helper.GetLoggerFactory().GetLogger().ForContext<PatientPreLoadEventHandler>(); //Construct a response object with default values kCura.EventHandler.Response retVal = new kCura.EventHandler.Response(); retVal.Success = true; retVal.Message = String.Empty; try { //Ensure that this is a new artifact if (this.ActiveArtifact.IsNew) { //Find the Co-Pay field and populate with a default value this.ActiveArtifact.Fields[CO_PAY_FIELD_GUID.ToString()].Value.Value = DEFAULT_CO_PAY; _logger.LogVerbose("Copay field {Guid} value changed to {DefaultCoPay}", CO_PAY_FIELD_GUID.ToString(), DEFAULT_CO_PAY); } } catch (System.Exception ex) { retVal.Success = false; retVal.Message = ex.ToString(); } return retVal; } /// <summary> /// Ensure that we always have access to these fields in the ActiveArtifact.Fields collection regardless if they are on the current layout or not /// </summary> public override kCura.EventHandler.FieldCollection RequiredFields { get { kCura.EventHandler.FieldCollection retVal = new kCura.EventHandler.FieldCollection(); retVal.Add(new kCura.EventHandler.Field(CO_PAY_FIELD_GUID)); return retVal; } } } }
In many cases, you may need to record additional details for your events, for example, to make them easier to identify. With Relativity you can add custom properties (metadata) to your logs. This can be done in the following ways:
var myClassLogger = _logger.ForContext<MyClass>();
var myLogger = _logger.ForContext(“CodeLocation”, “ZiggyStation”);
using (_logger.LogContextPushProperty("JobId", 12345)) { _logger.LogWarning("Any usage of _logger within this using context will now have the JobID property."); }
The following are the recommended best practices when using logging in your applications:
// Don't: Relativity.Logging.Log.Logger.LogDebug("Enabling agent" + Me.Name);
Instead, always use template properties to include variables in messages. Properties are passed in enclosed in braces:
// Do: Relativity.Logging.Log.Logger.LogDebug("Enabling agent {AgentName}", Me.Name);
This example shows what happens when you destructure a class object. Any objects that implement IEnumerable, like arrays, lists, tuples, dictionaries, etc., are destructured to JSON even without the @ symbol. Destructuring data types like strings or integers does not deserialize to a JSON string.
//Sample class namespace MySampleNamespace { public class MyObject { public string Description { get; set; } public int Value { get; set; } } } //Sample Logging Code MyObject testObject = new MyObject() { Description = "This is my object", Value = 100 }; //To get a destructured object put the @ symbol before the name of your message param name: {@...} Relativity.Logging.Log.Logger.LogDebug("Testing MyObject destructured - {@DeserializedMyObject}", testObject); //If you do not put the @ symbol the object will be outputted as if you did testObject.ToString() Relativity.Logging.Log.Logger.LogDebug("Testing MyObject not destructured - {NonDeserializedMyObject}", testObject); //Destructuring simple data types results in a non JSON serialized output, just like if string myString = "My Test String"; Relativity.Logging.Log.Logger.LogDebug("Testing myString destructured - {@MyString}", myString);
This is the output of the code:
With the @ symbol Message: Testing MyObject destructured - MyObject { Description: "This is my object", Value: 100 } Without the @ symbol Message: Testing MyObject destructured - "MySampleNamespace.MyObject" Simple data type with the @ symbol Message: Testing myString destructured - "My Test String"
Community Updates |
|||
Aero Developer FAQ | Evolving the Platform | Most recent release notes | |
Learn more | Learn more | Learn more |
Additional Resources |
|||
![]() |
![]() |
||
Access Third-Party Tools with GitHub | Create .NET Apps Faster with NuGet | ||
Visit github | visit nuget |