1646
Views
26
Comments
Solved
Tip: Auditing from inside Extensions
It is possible to write Audits to the application log from within your extensions, much like it can be done from your eSpace.

To achieve this, Hub Edition provides you with the function Audit(), inside the GenericExtendedActions namespace of its runtime. Anywhere inside your C# Extension, when you want to log an audit simply add the line

GenericExtendedActions.Audit( AppInfo.GetAppInfo().OsContext, <Message>, <ModuleName> );


and provide it with a suitable Message and ModuleName. These parameters have the exact same meaning as the equivalent parameters in the Audit Built-in Action in Service Studio. Please refer to Service Studio’s help documentation if you need more information on how the Audit functionality works.

Regards,


Miguel
Rank: #270
Solution

Thanks for making this information available, it is really useful. I would just like to add that the Audit method is deprecated. we should use the LogMessage method instead.


The updated version is:

GenericExtendedActions.LogMessage(AppInfo.GetAppInfo().OsContext, <Message>, <Module Name>);

Rank: #3839
Is it applicable to Java Version also ? 
Staff
Rank: #12
Hi Vasanth,

It is surely possible. Make sure you include the package outsystems.hubedition.runtimeplatform.
After this all you need is the following:

GenericExtendedActions.audit(AppInfo.getAppInfo().getOsContext(), "Module", "Message")
And that's it.

Cheers.

mvp_badge
MVP
Rank: #13
How do you log errors (which you may want to catch, but log in the error log)

Staff
Rank: #12
The exceptions thrown inside extensions are already logged by the platform (although there's a cap to prevent the lgo from flooding)...
mvp_badge
MVP
Rank: #7
Here's the answer you want, in C#. What it does is give you a "LogError" method that will send stuff to the ERROR LOG (not the audit log!) so that it ends up where you expect it to. That lets you handle errors inside a try/catch block, log the error the the log, and set an error message or otherwise gracefully handle the error... because I *hate* getting exceptions from Extensions, and therefore causing the transaction to be aborted... ugh.

Also, you'll note that my version handles the 2,000 character cap (just be careful what you feed this!) nicely, and just produces multiple log messages of 2,000 characters each.

At the top of your extension:

using OutSystems.HubEdition.RuntimePlatform.Log;

Then in your extension (replace "Mandrill" with the name of the extension!):
 

        private void LogError(WebException e)

        {

            var fullMessage = "MESSAGE: " + e.Message;

 

            using (var streamReader = new StreamReader(e.Response.GetResponseStream()))

            {

                fullMessage += "\nRESPONSE: " + streamReader.ReadToEnd();

            }

 

            fullMessage += "\nDATA:";

 

            foreach (var key in e.Data.Keys)

            {

                fullMessage += "\n" + key + ": " + e.Data[key];

            }

 

            LogError(fullMessage);

        }

 

        private void LogError(Exception e)

        {

            ErrorLog.StaticWrite(DateTime.Now, AppInfo.GetAppInfo().OsContext.Session.SessionID,

            AppInfo.GetAppInfo().eSpaceId, AppInfo.GetAppInfo().Tenant.Id,

            AppInfo.GetAppInfo().OsContext.Session.UserId, e.Message, e.ToString(), "Mandrill");

        }

 

        private void LogError(string message)

        {

            if (message.Length <= 2000)

            {

                ErrorLog.StaticWrite(DateTime.Now, AppInfo.GetAppInfo().OsContext.Session.SessionID,

                AppInfo.GetAppInfo().eSpaceId, AppInfo.GetAppInfo().Tenant.Id,

                AppInfo.GetAppInfo().OsContext.Session.UserId, message, "", "Mandrill");

            }

            else

            {

                for (var currentPosition = 0; currentPosition <= message.Length - 1; currentPosition += 2000)

                {

                    var endPosition = Math.Min(message.Length - currentPosition, currentPosition + 2000);

 

                    ErrorLog.StaticWrite(DateTime.Now, AppInfo.GetAppInfo().OsContext.Session.SessionID,

                        AppInfo.GetAppInfo().eSpaceId, AppInfo.GetAppInfo().Tenant.Id,

                        AppInfo.GetAppInfo().OsContext.Session.UserId, message.Substring(currentPosition, endPosition), "", "Mandrill");

                }

            }

        }

mvp_badge
MVP
Rank: #7
Jose -

And what error are you getting?

J.Ja
Rank: #625
Hi James,

I'm getting none:



Is there a file were Integration Studio writes the log?

Thx!
mvp_badge
MVP
Rank: #7
Jose -

Ah, you've encountered one of the first issues I had with OutSystems! This dialog is VERY confusing.

Click on the *second from the bottom line* (the one that says ".NET Compilation" and "Compiler Error") and the error will be displayed at the bottom.

J.Ja
Rank: #625
Hi Justin,

Thanks for the tip!

I had 2 errors:
1) I didn't have SDK installed;
2) The compiler complain about 'var', throwing error CS0246.

As my time was short to dig into the problem, just changed the implicit 'var' to explicit types...

Thx,
JA
mvp_badge
MVP
Rank: #7
Jose -

Yes, that's another known Integration Studio problem... not a "bug", just an "aggravation".

You need to change Integration Studio's .NET options to use the 3.5 .NET compilation, by making the compiler options line look like this:

/nologo /verbosity:minimal /target:Rebuild /property:Configuration=Release /ToolsVersion:3.5

J.Ja
Rank: #625
Hi Justin,

Indeed, I was using the IS' default (/nologo /verbosity:minimal /target:Rebuild /property:Configuration=Release).

Tomorrow, at the office, I'll test with the new settings.

Thanks again for the help,
JA
mvp_badge
MVP
Rank: #24
And how about nowadays, folks?

How can I manipulate exceptions from inside an extension?
mvp_badge
MVP
Rank: #25
Just for the record, the Audit function changed slightly in the latest version of ServiceStudio.

Here's the updated version:

GenericExtendedActions.Audit(AppInfo.GetAppInfo().OsContext, "Module", "Message");
Rank: #270
Solution

Thanks for making this information available, it is really useful. I would just like to add that the Audit method is deprecated. we should use the LogMessage method instead.


The updated version is:

GenericExtendedActions.LogMessage(AppInfo.GetAppInfo().OsContext, <Message>, <Module Name>);

Rank: #391

Excuse my ignorance but I'm still finding my way in Outsystems, where do you find the error logs as they're not appearing in Service Center?

Rank: #391

Apologies for the delay in replying, I was busy working on other things.

I still can't see anything under Monitoring>General either.  I have added your code and...

GenericExtendedActions.LogMessage(AppInfo.GetAppInfo().OsContext, "MyTestComment", "MyVoidName");

What am I missing?

Rank: #391

Ok cancel that, it has now mysteriously appeared and I've no idea why but not going to complain lol.

Rank: #375

Is this still working? I can't see anything on General Tab.

Rank: #391

It works for me currently. Have you implemented the necessary code above in your solution?

Rank: #375

Using this code:

GenericExtendedActions.LogMessage(AppInfo.GetAppInfo().OsContext, "MyTestComment", "MyVoidName");

For me, nothing appears on General Tab...

Rank: #391

Try adding these as well....


        private void LogError(WebException e)
        {
            var fullMessage = "MESSAGE: " + e.Message;
            using (var streamReader = new StreamReader(e.Response.GetResponseStream()))
            {
                fullMessage += "\nRESPONSE: " + streamReader.ReadToEnd();
            }
            fullMessage += "\nDATA:";
            foreach (var key in e.Data.Keys)
            {
                fullMessage += "\n" + key + ": " + e.Data[key];
            }
            LogError(fullMessage);
        }


        private void LogError(Exception e)
        {
            ErrorLog.StaticWrite(DateTime.Now, AppInfo.GetAppInfo().OsContext.Session.SessionID,
            AppInfo.GetAppInfo().eSpaceId, AppInfo.GetAppInfo().Tenant.Id,
            AppInfo.GetAppInfo().OsContext.Session.UserId, e.Message, e.ToString(), "AsposeWordIntegration");
        }


        private void LogError(string message)
        {
            if (message.Length <= 2000)
            {
                ErrorLog.StaticWrite(DateTime.Now, AppInfo.GetAppInfo().OsContext.Session.SessionID,
                AppInfo.GetAppInfo().eSpaceId, AppInfo.GetAppInfo().Tenant.Id,
                AppInfo.GetAppInfo().OsContext.Session.UserId, message, "", "AsposeWordIntegration");
            }
            else
            {
                for (var currentPosition = 0; currentPosition <= message.Length - 1; currentPosition += 2000)
                {
                    var endPosition = Math.Min(message.Length - currentPosition, currentPosition + 2000);
                    ErrorLog.StaticWrite(DateTime.Now, AppInfo.GetAppInfo().OsContext.Session.SessionID,
                        AppInfo.GetAppInfo().eSpaceId, AppInfo.GetAppInfo().Tenant.Id,
                        AppInfo.GetAppInfo().OsContext.Session.UserId, message.Substring(currentPosition, endPosition), "", "AsposeWordIntegration");
                }
            }
        }

So...

Now doing this:

GenericExtendedActions.LogMessage(AppInfo.GetAppInfo().OsContext, "Who you gonna call?", "Ghostbusters!");

crashes with this error:

Object reference not set to an instance of an object.

Awesome!

I'm on Version 10.0.1014.0 of the platform, if that helps.

mvp_badge
MVP
Rank: #2

Hi Carlos,

Are you calling the Action in the Extension from a Module, or are you trying to use it in Visual Studio itself, in a test project of some sorts? The "Object reference" error is probably because GetAppInfo() returns a null object, which would be the case when you call it outside a Module.

I am, yes.

Luckily I managed to figure out what was wrong with the extension (pro tip: if you're calling a web service, make sure you use the correct endpoint ??) so I'm OK for now.

Also, I didn't even know you could use the OutSystems references outside of an extension. To be fair, these days creating extensions is mostly only needed for quirky stuff like ancient SOAP web services that don't really follow the standards, so I'm definitely not an expert at it.