To help BIM Managers train or punish their Revit users, I was asked at RTC in Delft if we can use the API to figure out which users are responsible for each warning in your Revit file.
Here’s how that can be done by writing all warnings to a log file and then comparing warnings in the current file with those in the log.
public void RegisterFailureReporter()
{
Application app = this.Application;
Document doc = this.ActiveUIDocument.Document;
if (doc.PathName == "")
{
TaskDialog.Show("Error","Please save the file and then repeat this command.");
return;
}
app.FailuresProcessing += FailureReporter;
}
private void FailureReporter(object sender, Autodesk.Revit.DB.Events.FailuresProcessingEventArgs args)
{
FailuresAccessor fa = args.GetFailuresAccessor();
Document doc = fa.GetDocument();
using (StreamWriter sw = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Path.GetFileName(doc.PathName) + " Warning Creation Log.csv"), true))
{
foreach (FailureMessageAccessor fma in fa.GetFailureMessages(FailureSeverity.Warning))
{
sw.Write(DateTime.Now + "," + fa.GetDocument().Application.Username + ",");
sw.Write(fma.GetDescriptionText().Replace(Environment.NewLine,"") + "," );
foreach (ElementId id in fma.GetFailingElementIds())
{
// use UniqueId instead of ElementId because the UniqueId is stable across Save To Central while the ElementId property may change.
sw.Write(doc.GetElement(id).UniqueId + ",");
}
sw.Write(Environment.NewLine);
}
}
}
public void CheckCurrentWarningsInLog()
{
Document doc = this.ActiveUIDocument.Document;
if (doc.PathName == "")
{
TaskDialog.Show("Error","Please save the file and then repeat this command.");
return;
}
using (StreamReader warningsHTMLReader = new StreamReader(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Path.GetFileNameWithoutExtension(doc.PathName) + "_Error Report.html")))
{
string line = "";
while ((line = warningsHTMLReader.ReadLine()) != null)
{
if (!line.Contains(": id "))
continue;
string[] row = System.Text.RegularExpressions.Regex.Split(line, "id ");
string id1 = row[1].Split(' ')[0];
string uniqueId1 = doc.GetElement(new ElementId(int.Parse(id1))).UniqueId;
string uniqueId2 = null;
if (row.Count() == 3) // there are two element ids in this row
{
string id2 = row[2].Split(' ')[0];
uniqueId2 = doc.GetElement(new ElementId(int.Parse(id2))).UniqueId;
}
using (StreamReader warningLogReader = new StreamReader(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Path.GetFileName(doc.PathName) + " Warning Creation Log.csv")))
{
string lineLog = "";
while ((lineLog = warningLogReader.ReadLine()) != null)
{
if (lineLog.Contains(uniqueId1) || (uniqueId2 != null && lineLog.Contains(uniqueId1) && lineLog.Contains(uniqueId2)))
{
using (StreamWriter sw = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Path.GetFileName(doc.PathName) + " Current Warnings With User Info.csv"), true))
{
sw.WriteLine(lineLog);
}
break;
}
}
}
}
}
}
Hi Harry, this is pretty neat. I’m quite new to the API and is trying to convert this macro to an Add-in, but is having a hard time finding a way to get the RegisterFailureReporter to run on startup. Is this possible or do I have to run it through an externalcommand?
Thanks
Andy
Hi Andy,
Glad you like it. The registration can be done during the OnStartup method of an External Application. If you are new to the API, you might find it worthwhile to take my class at http://www.udemy.com/revitapi. Lecture 29 explains how OnStartup can be used.
Harry
Hi Harry,
Will this work as far back as Revit 2012?
probably
I’ll give it a try. Our oldest version installed is still 2012.
Hi,
I’m new to API and would like to implement something similar to the video above in my Revit workflow.
How do I set up the API in Revit with the coding provided underneath the video?
Hi,
Please take a look at this post
https://boostyourbim.wordpress.com/2013/02/15/how-to-use-boost-your-bim-source-code-to-create-working-macros/
You might also be interested in my video course at bitly.com/revitapi for a more comprehensive overview of the Revit API
Thanks Harry, I’ll look into it and let you know how it goes.
I am receiving this error
The type or namespace name ‘StreamReader’ could not be found (are you missing a using directive or an assembly reference?)
Probably you are missing a using statement for System.IO. If you look at the online help for StreamReader (https://msdn.microsoft.com/en-us/library/system.io.streamreader%28v=vs.110%29.aspx) it identifies it as being in the namespace System.IO
In general, I recommend putting all of the using statements at the top of your macro source file
https://boostyourbim.wordpress.com/2012/12/23/using-statements/