DX Unified Infrastructure Management

Expand all | Collapse all

When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

  • 1.  When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Posted Dec 18, 2018 02:22 PM

    I have an LUA script that cleans HTML tags out of my alarm message, and what I am trying to do is have it triggered by the Auto Operator on arrival. So on arrival this script would be ran:

     

    First step is to pull in the alarm and assign the message to a string, this is the part I am not sure of can I use the alarm.get() to do something like this?

        

    s = alarm.get()

    local t = tostring(s) 

     

    Than I can run the string through the rest of my script that cleans out the HTML tags and gives me back the clean string:

     

    local cleaner = {
    { "&", "&" }, -- decode ampersands
    { "—", "-" }, -- em dash
    { "’", "'" }, -- right single quote
    { "“", "\"" }, -- left double quote
    { "”", "\"" }, -- right double quote
    { "–", "-" }, -- en dash
    { " ", " " }, -- non-breaking space
    { "<br ?/?>", "\n" }, -- all <br> tags whether terminated or not (<br> <br/> <br />) become new lines
    { "</p>", "\n" }, -- ends of paragraphs become new lines
    { "(%b<>)", "" }, -- all other html elements are completely removed (must be done last)
    { "\r", "\n" }, -- return carriage become new lines
    { "[\n\n]+", "\n" }, -- reduce all multiple new lines with a single new line
    { "^\n*", "" }, -- trim new lines from the start...
    { "\n*$", "" }, -- ... and end
    }


    for i=1, #cleaner do
    local cleans = cleaner[i]
    t = string.gsub( t, cleans[1], cleans[2] )
    end

     

    Then I want the alarm to use the cleaned string as the alarm message. Anyone have any idea on how to finish to accomplish this and if I am pulling the alarm message properly into the script from the auto operator?



  • 2.  Re: When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Posted Dec 18, 2018 05:47 PM

    Yes though the alarm.get() returns a table, not a string.

     

    https://c.na53.content.force.com/servlet/fileField?id=0BE60000000PBnT 

     

    And you may want to do this in a preprocessing script instead otherwise the alarm will exist for a period of time with the illegal characters every time it is created or updated.



  • 3.  Re: When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Posted Dec 18, 2018 05:49 PM

    And that link is to the nas tech doc. It's off the old Salesforce site which you may or may not have access to. Maybe someone can post an updated link if one exists. 



  • 4.  Re: When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Broadcom Employee
    Posted Dec 19, 2018 04:06 AM

    You need to extract the message from the alarm using…

    Local t=s.message

     

    Then you can run your message through your cleaner.

    Should work fine

    cheers



  • 5.  Re: When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Posted Dec 19, 2018 07:41 AM

    rowan.collis - So if I do something like this it should be ok? (Check the second line in BOLD) - Also once I run the string through the cleaner how do I send the newly created message (whith no HTML tags) to the alarm to be used? Or will is do that automatically?

     

    s = alarm.get()

    local t = s.message

    -- list of strings to replace (the order is important to avoid conflicts)

    local cleaner = {

    { "&amp;", "&" }, -- decode ampersands

    { "&#151;", "-" }, -- em dash

    { "&#146;", "'" }, -- right single quote

    { "&#147;", "\"" }, -- left double quote

    { "&#148;", "\"" }, -- right double quote

    { "&#150;", "-" }, -- en dash

    { "&#160;", " " }, -- non-breaking space

    { "<br ?/?>", "\n" }, -- all <br> tags whether terminated or not (<br> <br/> <br />) become new lines

    { "</p>", "\n" }, -- ends of paragraphs become new lines

    { "(%b<>)", "" }, -- all other html elements are completely removed (must be done last)

    { "\r", "\n" }, -- return carriage become new lines

    { "[\n\n]+", "\n" }, -- reduce all multiple new lines with a single new line

    { "^\n*", "" }, -- trim new lines from the start...

    { "\n*$", "" }, -- ... and end

    }

    -- clean html from the string

    for i=1, #cleaner do

    local cleans = cleaner[i]

    t = string.gsub( t, cleans[1], cleans[2] )

    end

     

    garin.lamme - Yes I originally wanted to do this in a pre-processing rule, and I am going to try the above that I posted to Rowan, however like I said above, once the string is cleaned how do I send the message (the new string) back to the alarm to be used as the message in the console?



  • 6.  Re: When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Broadcom Employee
    Posted Dec 19, 2018 10:11 AM

    Just need the following at the end

    s.message = t

    alarm.set(s)



  • 7.  Re: When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Posted Dec 20, 2018 08:14 AM

    RowanCollis I get no output at all from this:

     

    s = alarm.get()

    t = s.message

    -- list of strings to replace (the order is important to avoid conflicts)

    cleaner = {

    { "&amp;", "&" }, -- decode ampersands

    { "&#151;", "-" }, -- em dash

    { "&#146;", "'" }, -- right single quote

    { "&#147;", "\"" }, -- left double quote

    { "&#148;", "\"" }, -- right double quote

    { "&#150;", "-" }, -- en dash

    { "&#160;", " " }, -- non-breaking space

    { "<br ?/?>", "\n" }, -- all <br> tags whether terminated or not (<br> <br/> <br />) become new lines

    { "</p>", "\n" }, -- ends of paragraphs become new lines

    { "(%b<>)", "" }, -- all other html elements are completely removed (must be done last)

    { "\r", "\n" }, -- return carriage become new lines

    { "[\n\n]+", "\n" }, -- reduce all multiple new lines with a single new line

    { "^\n*", "" }, -- trim new lines from the start...

    { "\n*$", "" }, -- ... and end

    }

    -- clean html from the string

    for i=1, #cleaner do

    cleans = cleaner[i]

    t = string.gsub( t, cleans[1], cleans[2] )

    end

     

    s.message = t

    alarm.set(s)

     

     

     

     

    not sure if I did something wrong but I added those at the bottom, This is setup as a pre-processing rule("Custom") and I choose my script. And When I run an alarm through I still get the same alarm, however if I take that alarm and hardcode it into the script as a static variable the script cleans the string up properly so it seems I am not getting the message from the alarm and not passing the message back go the alarm?



  • 8.  Re: When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Posted Dec 20, 2018 12:35 PM

    Hi, did you get this to work yet? Above you noted that this is set up as a pre-processing script, in which case it will not work. Functions such as alarm.set() are not available for use in pre-processing scripts.

    For this to be used as a pre-processing script it would look something like this:

    Note: Using Garin's suggestion of eliminating the table of tables and looping

     

    -- clean html from the event message string

    event.message = string.gsub( event.message, "&amp;", "&" ) -- decode ampersands

    event.message = string.gsub( event.message, "&#151;", "-" ) -- em dash

    event.message = string.gsub( event.message, "&#146;", "'" ) -- right single quote

    event.message = string.gsub( event.message, "&#147;", "\"" ) -- left double quote

    event.message = string.gsub( event.message, "&#148;", "\"" ) -- right double quote

    event.message = string.gsub( event.message, "&#150;", "-" ) -- en dash

    event.message = string.gsub( event.message, "&#160;", " " ) -- non-breaking space

    event.message = string.gsub( event.message, "<br ?/?>", "\n" ) -- all <br> tags whether terminated or not (<br> <br/> <br />) become new lines

    event.message = string.gsub( event.message, "</p>", "\n" ) -- ends of paragraphs become new lines

    event.message = string.gsub( event.message, "(%b<>)", "" ) -- all other html elements are completely removed (must be done last)

    event.message = string.gsub( event.message, "\r", "\n" ) -- return carriage become new lines

    event.message = string.gsub( event.message, "[\n\n]+", "\n" ) -- reduce all multiple new lines with a single new line

    event.message = string.gsub( event.message, "^\n*", "" ) -- trim new lines from the start...

    event.message = string.gsub( event.message, "\n*$", "" ) -- ... and end

     

     

    return(event)



  • 9.  Re: When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Posted Dec 19, 2018 03:30 PM

    A couple things to keep in mind with Lua and programing within UIM:

     

    "Lua" is a proper name, it is not an abbreviation. So LUA is incorrect capitalization - Grin...

     

    Always test your return variables - UIM is like a toddler, it will usually do what you expect but every so often it will do something that's completely unexpected. 

     

    So

    s = alarm.get()

    should be followed by 

    if ( s ~= nil ) then

       -- your code here

    else

       -- your error handling here

    end

     

    Lua has two sets of scoping in a script - the outermost level (where you define s and t) is a global list that's searched sequentially. That means it will be slow. Anything scoped inside that is in a hash table that's on the stack and so much faster to use. You can dramatically (sometimes) increase the speed of your code by enclosing all the code within a do/end. That takes your variables out of the global scope and puts them in the local scope.

     

    Always define your variables -  

    local s = alarm.get()

    is more proper.

     

    Tables are just tables. It is important not to draw too many assumptions about them. Your initialization is correct because in the absence of an id, Lua uses a sequential integer that starts a 1 and increases predictably. It is cleaner and more obvious though to force the assignment so instead of

    local cleaner = {

    { "&amp;", "&" }, -- decode ampersands

    { "&#151;", "-" }, -- em dash

    { "&#146;", "'" }, -- right single quote

     

    I'd suggest using

    local cleaner = {

    { [1] = "&amp;", "&" }, -- decode ampersands

    { [2] = "&#151;", "-" }, -- em dash

    { [3] = "&#146;", "'" }, -- right single quote

     

    The '#' table size operator is somewhat implementation independant. It will probably be right in the simple usage here but as soon as you start adding and removing items from a table, all bets are off. It is better to iterate over a table with pairs()/ipairs() or to use the looping construct with a terminator like while (cleaner[i] ~= nil)

     

     You current code calls string.gsub 14 times. it would be faster to have at the beginning (note replacing the '.' with '_'):

    do

       local string_gsub = string.gsub

     

    then in the for loop, use the local variable:

    t = string_gsub( t, cleans[1], cleans[2] )

     

    The string object will be in that global list of objects and hence slower to access than a local variable. It's not of value if you need the function only once but at some point (you'd have to test to find the actual number) it's faster to take the extra step to create and assign the local variable. My experience is that 14 calls is enough to make a difference.

     

    And finally, as an overall comment, I appreciate the design of creating a table to drive the following code because it lends itself to easy understanding and maintenance but AO scripts aren't homework assignments in a CS class, they are smack dab in the middle of the limiting factor in processing alarm flow. Every CPU cycle can be important. So, consider ditching the table and looping structure and just having the 14 gsub calls in order. Messier but you eliminate all the table creation and accessing, the I variable, the cleans variable, and the looping structure.

     

    Oh, and make sure you understand the impact of on arrival/on overdue/etc settings on the profile itself.

     

    Just my 7 cents on the script

     

    -Garin 



  • 10.  Re: When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Posted Dec 19, 2018 03:32 PM

    Sorry, one mistake

    I'd suggest using

    local cleaner = {

    { [1] = "&amp;", "&" }, -- decode ampersands

    { [2] = "&#151;", "-" }, -- em dash

    { [3] = "&#146;", "'" }, -- right single quote

     

    should be

     

    I'd suggest using

    local cleaner = {

    [1] = { "&amp;", "&" }, -- decode ampersands

    [2] = { "&#151;", "-" }, -- em dash

    [3] = {  "&#146;", "'" }, -- right single quote



  • 11.  Re: When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Posted Dec 20, 2018 08:16 AM

    Garin

     

    Thanks for the English lesson, I will make sure I refer to it properly LUA.

     

    Also yes, In many ways this can be cleaned up and improved. The idea was to just see it work for starters. Then I can go back and clean it up and make it more efficient. I appreciate your suggestions though and I will make changes. However I am still stuck at the start where I have not been able to get it to work yet as it sits now.



  • 12.  Re: When using an Auto Operator with a LUA script, the alarm.get() will that pull the alarm from the current alarm that triggered the Auto Operator?

    Posted Dec 20, 2018 11:14 AM

    Your simplest AO script will look like:

     

    s = alarm.get() -- Retrieve the alarm contents into s

    s.message = "New alarm message" -- Change some part of the alarm

    alarm.set(s) -- Put the alarm back out onto the Nimbus bus to be reprocessed

     

    It looks like the most recent whole posting of your script satisfies this.

     

    There are a couple things to check:

     

    If you right click on the AO in the nas GUI in IM you can select "View Activity" - confirm that it's actually being run - it's possible everything is right in the code but the filter criteria isn't matching the event.

     

    Pay attention to the color of the entries - they should all be in black - any other color indicates a problem. Similarly the "Status" column will indicate the return status of the script - should be 0.

     

    THe nas.log file will contain any output from the script, errors or otherwise. Have you checked that?

     

    You should see entries like this when the script is triggered:

    nas: ExecEvent: IMMEDIATE rule='My AO Rule Name', nimid=XX12312018-00171, ACTION:script

     

    I'd suggest adding to the beginning of the script something like 

    print("This is the start of my AO.")

     

    And throughout printing things like the message in the for loop, and reaching the end of the script.

     

    And it would be worthwhile to post a picture of the AO profile configuration from the nas for comment.