Nice3point.Revit.Logging
2027.0.0
Prefix Reserved
dotnet add package Nice3point.Revit.Logging --version 2027.0.0
NuGet\Install-Package Nice3point.Revit.Logging -Version 2027.0.0
<PackageReference Include="Nice3point.Revit.Logging" Version="2027.0.0" />
<PackageVersion Include="Nice3point.Revit.Logging" Version="2027.0.0" />
<PackageReference Include="Nice3point.Revit.Logging" />
paket add Nice3point.Revit.Logging --version 2027.0.0
#r "nuget: Nice3point.Revit.Logging, 2027.0.0"
#:package Nice3point.Revit.Logging@2027.0.0
#addin nuget:?package=Nice3point.Revit.Logging&version=2027.0.0
#tool nuget:?package=Nice3point.Revit.Logging&version=2027.0.0
Logging library for Revit
Write logs for your Revit add-ins using Microsoft.Extensions.Logging. The library adds the journal of the Revit session as a logging destination and writes every record there as a journal comment.
Log levels, filtering, scopes and message templates are handled by Microsoft.Extensions.Logging.
Installation
You can install this library as a NuGet package.
The packages are compiled for specific versions of Revit. To support different versions of libraries in one project, use the RevitVersion property:
<PackageReference Include="Nice3point.Revit.Logging" Version="$(RevitVersion).*"/>
Writing your first record
Start by adding the provider to the host of your application:
public class Application : ExternalApplication
{
public override void OnStartup()
{
var builder = Host.CreateApplicationBuilder();
builder.Logging.AddRevitJournal(Application.ControlledApplication);
builder.Build().Start();
}
}
ServiceCollection works the same way when your add-in has no host:
public class Application : ExternalApplication
{
public override void OnStartup()
{
var services = new ServiceCollection();
services.AddLogging(logging => logging.AddRevitJournal(Application.ControlledApplication));
var serviceProvider = services.BuildServiceProvider();
}
}
Inject ILogger<T> and write a record:
public class UpdateService(ILogger<UpdateService> logger)
{
public void CheckUpdates()
{
logger.LogInformation("Checking updates");
}
}
The record appears in the journal of the running session:
'C 05-Sep-2026 22:48:59.703; 0:< RevitAddin_INFORMATION { RevitAddin.Services.UpdateService: Checking updates }
Revit stores journals in %LocalAppData%\Autodesk\Revit\Autodesk Revit {version}\Journals.
Record format
The library writes the record, Revit writes the beginning of the line:
' 0:< RevitAddin_WARNING { RevitAddin.Services.SettingsService: Settings file is missing }
'C 05-Sep-2026 22:48:59.703; 0:< RevitAddin_ERROR { RevitAddin.Services.UpdateService: Update service error }
A record has the following format:
{ApplicationName}_{Level} { {Category}[{EventId}] => {Scope} => {Scope}: {Message}
{Exception} }
The braces bound the record. An exception occupies the lines that follow the message, and Revit opens each of them with an apostrophe:
' 0:< RevitAddin_ERROR { RevitAddin.Services.UpdateService: Update service error
'System.Net.Http.HttpRequestException: Response status code does not indicate success: 403.
' at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode() }
Text you log needs no escaping. Revit comments out every line of a record, including a line that contains a journal command.
Log levels
The provider alias is RevitJournal. Set the minimum level for the journal separately from the other providers:
{
"Logging": {
"LogLevel": {
"Default": "Information"
},
"RevitJournal": {
"LogLevel": {
"Default": "Error"
}
}
}
}
The same filter in code:
builder.Logging.AddFilter<RevitJournalLoggerProvider>(null, LogLevel.Error);
A journal keeps the whole session and the user sends it to Autodesk with an error report. Keep the minimum level at Warning or Error in a release build.
Options
| Option | Default | Description |
|---|---|---|
ApplicationName |
Name of the assembly that called AddRevitJournal |
Opens the record token and identifies your add-in in a journal |
IncludeCategory |
true |
Writes the category of the record |
IncludeEventId |
false |
Writes the event id in square brackets after the category |
IncludeScopes |
false |
Writes the scopes of the record, joined by => |
IncludeTimestamp |
true |
Opens the journal line with the time stamp of the session |
SingleLine |
false |
Collapses the line breaks of the message and of the exception |
Configure them when you add the provider:
builder.Logging.AddRevitJournal(Application.ControlledApplication, options =>
{
options.ApplicationName = "RevitAddin";
options.IncludeScopes = true;
});
Options also bind from the Logging:RevitJournal section:
{
"Logging": {
"RevitJournal": {
"IncludeScopes": true,
"IncludeEventId": true
}
}
}
Configuration is applied first, and the options delegate overrides it.
IncludeTimestamp
Revit writes the time stamp in the format the rest of the journal uses:
'C 05-Sep-2026 22:48:59.703; 0:< RevitAddin_ERROR { ... }
Turn it off to shorten the line. The nearest stamped line above then dates the record:
' 0:< RevitAddin_ERROR { ... }
Scopes
IncludeScopes writes the scopes of the record, from the outermost one:
using (logger.BeginScope("Startup"))
using (logger.BeginScope("Document {Title}", document.Title))
{
logger.LogError("Update service error");
}
' 0:< RevitAddin_ERROR { RevitAddin.Services.UpdateService => Startup => Document Snowdon Towers: Update service error }
Multithreading
A record is written on the thread that logged it, both inside and outside the Revit API context. Wrap nothing in an external event and marshal nothing onto the Revit thread:
await Task.Run(() =>
{
logger.LogError("Update service error");
});
Revit serializes the writes, and records never mix with each other.
Custom formatter
Inherit RevitJournalFormatter to write your own record format:
public class MessageOnlyFormatter : RevitJournalFormatter
{
public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeProvider? scopeProvider, StringBuilder record)
{
record.Append(logEntry.LogLevel)
.Append(' ')
.Append(logEntry.Formatter(logEntry.State, logEntry.Exception));
}
}
Register it after the provider:
builder.Logging.AddRevitJournal(Application.ControlledApplication);
builder.Logging.AddRevitJournalFormatter<MessageOnlyFormatter>();
The record buffer is empty on entry and reused between records. Leave it empty to discard a record.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-windows7.0 is compatible. |
-
net10.0-windows7.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
- Microsoft.Extensions.Logging.Configuration (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.