Last report time in days

(imported comment written by MBARTOSH)

I think Omkar just wants the relevance for (current day - last report) in days. It seems like a good ideas to me also.

(imported comment written by Darknight)

what i a looking for is teh relevance which can give me (now - last report time) in days which in turn i can compare with some threshold valuses (30 days , 60 days , 90 days) and then output value like “more than 30 days” or “less than 30 days” or more than 90 days" or less than 90 days.

Could you please help me in building this logic via relevane.

(imported comment written by Tim.Rice)

Ok. Now answer the question … Where is relevance evaluated?

the answer to this would be “The Agent” who then reports the information to the server. To further complicate matters, if I recall correctly, the client doesn’t even set the Last Report Time. The Relay/Server does when it receives the report from the Agent.

You can use WebReports to get what you are looking for since the information is in the database. Create a Filter on “Last Report Time” and “less than” “30” “days”

i think you’ll need to use multiple reports, but you should be able to get the machines that meet your criterion.

(imported comment written by Darknight)

Thanks Tim.Rice for your help and information.

So is it like there is no way to create a separate property which will have (now - last report time) in days via relevance. In our infrastructure client have a requirement to have a separate property which can tell him this calculation in days format.

or is it possible to somehow use the value of reserved property provided by IEM that is “Last Report Time” and then build the above logic via relevance

(imported comment written by MattPeterson)

It looks like the clients can evaluate “last report time”. The statement below should work.

((now

(apparent registration server time))

/

day)

as

string

&

" days"

(imported comment written by Tim.Rice)

Again, the problem is that “Relevance” is evaluated by the Agent not the console or database, so nothing gets updated in the database until the Agent reports it.

Why does the client need to know the last report time in Days? Maybe there is a different way to solve the requirement?

(imported comment written by Darknight)

Thanks MattPeterson for reply … but i received the below error :

q:
((now

(apparent registration server time))

/

day)

as

string

&

" days"

E:
No inspector context.

@Tim.Rice…i got your point but is there any way by which i can create a property which will give the result same or equivalent to :

((now - last report time) / days)…i am not sure how to procees with this.

Also our client erquirement is to have a separate property which can provide above results in day format.

(imported comment written by Darknight)

Can someone please provide a hint or solution for this.

(imported comment written by jgstew)

As Tim.Rice points out, this cannot be done through client relevance.

You could do this through Session Relevance through Web Reports or an API.

(imported comment written by Darknight)

thanks jgstew… as i am new to the relevance language , i request you te kindly let me know how session relavance will be usefull in this case

(imported comment written by JasonWalker)

There are several ways to do this.

First off, Welcome to Relevance! Lot of terms in here that you can find out more about by Googling; but the BigFix documentation is scattered and poor, so if you don’t know these terms it’s hard to find them. One of the better references for both Client Relevance and Session Relevance is at
https://support.bigfix.com/inspectors/Action%20Objects_Any.html

“Session Relevance” is evaluated by the server. Useful in the BigFix Console, Web Reports, Dashboards, etc. Since Session Relevance is evaluated by the server, not the client, you can’t use Session Relevance to determine things like fixlet applicability. You can use it in the administrative tools.

“Client Relevance” is evaluated by the client. It can do things like determine whether a fixlet is applicable, or provide an answer for an Analysis.

To test Session Relevance, easiest way is to use the Presentation Debugger. In the BigFix Console, press “CTRL-ALT-SHIFT-D” (no, I’m not kidding). This brings up the Debugger. Click the checkbox in the upper left that says “Show Debug Menu”, then you can close the debug window. If you look at the menu bar at the top of the console, you’ll see a new option “Debug” right next to “Help”. Select Debug->Presentation Debugger to get to a place where you can evaluate Session Relevance.

In Session Relevance, you can do an evaluation like

(name of it, (now - last report time of it) / day ) of bes computers

and get a result like

hostname1, 0

hostname2, 29

That’s usable in the Console, custom Dashboards, and in Web Reports.

If this needs to be configured as a Client Setting, there’s a similar thing you can do on the client. Looking at your earlier post -

q:
((now

(apparent registration server time))

/

day)

as

string

&

" days"

E:
No inspector context.

The problem there is that the Fixlet Debugger, by default, runs in a separate process and cannot look at realtime client values. You need to select Debug -> Evaluate Using -> Local Client Evaluator in order to have the Fixlet Debugger run the Q: through the real BigFix Client. Note this command then ends up in the normal client polling cycle, so it will run a LOT slower than using the Fixlet Debugger Evaluator. Then I think what you’re looking for is:

q: ((now - last report time of client) / day) as string & " days"

A: 0 days

As has been pointed out, the client can evaluate this any time, but it won’t report the value back to the server until…it reports in to the server. So the value that’s being reported is always going to be “now”. So this might be useful to run in a Client Dashboard, or maybe as Relevance on a Policy Action, but you aren’t going to see much in the way of useful results from this in the console.

Where I’ve done something similar is to use an Analysis that creates a property in a date format that’s easier to sort. While it’s not easy to sort the “Last Report Time” client property because it’s written out like “Sunday, June 6 2014 …”, you could use an Analysis to report the date as YYYY_MM_DD so it sorts properly:

q: (year of it as string & “" & month of it as two digits as string & "” & day_of_month of it as two digits as string) of date (local time zone) of now

A: 2014_06_08

(imported comment written by Darknight)

thanks a trillion Jasonwalker for explaining me the use of session relevance…

i have tried to use the session rlevance that is presenttaion debugger to perform the below logic:

  1. if (now - last report time of it) / day ) of bes computers is less than or equal to 30 then echo “less than 30 days”

  2. if (now - last report time of it) / day ) of bes computers is greater than 30 but less than or equal to 60 then echo “greater than 60 days”

  3. if (now - last report time of it) / day ) of bes computers is greater than 60 days but less than or equal to 90 days then echo " greater than 60 days"

  4. if (now - last report time of it) / day ) of bes computers is greater than or equal to 90 days then echo "greater than 90 days…

relevance i have tried to built is :

if

((
0

<=

((now

last report time

of

it
)

/

day )
of

bes computer)

AND

(((now

last report time

of

it
)

/

day )
of

bes computer

<=

30
))

then

(
“Less Than 30 Days”
)

else

if

((
30

<

((now

last report time

of

it
)

/

day )
of

bes computer)

AND

(((now

last report time

of

it
)

/

day )

of

bes computer
<=

60
))

then

(
“Greater than 30 Days”
)

else

if

((
60

<

((now

last report time

of

it
)

/

day )
of

bes computer)

AND

(((now

last report time

of

it
)

/

day )
of

bes computer

<=

90
))

then

(
“Greater Than 60 Days”
)

else

if

(((now

last report time

of

it
)

/

day )
of

bes computer

=

90
)

then

(
“Greater Than 90 Days”
)

else

(
“error in evaluating”
)

which gave error :

Error: Singular expression refers to non-unique object.

Could you please let me know where i have gone wrong here…

(imported comment written by JasonWalker)

In the first four relevance statements, you’re looking at (last report time) of bes computer
s (plural)

Where in the final statement you’re looking at bes computer (singular). You’d need to wrap that all in parentheses, so you’d be looking at the last report time of individual computers -

(last report time of it) of bes computers

But I don’t think this will do what you want. All you’re returning then is “Less than 30 Days”, without the names or client IDs of the computers. What I think you’d want is more along the lines of

Separate statements:

“Less than 30 Days:”

&

concatenation

", "

of

names

of

bes computers

whose

(last report time

of

it

<

now

30

day)

or

(name of it & “:” & (if it < 30 then “less than 30” else if it < 60 then “between 30 and than 60” else if it < 90 then “between 60 and 90” else “more than 90”) of ((now - last report time of it) / day)) of bes computers

Hope this helps

(imported comment written by Darknight)

thanks a lot jasonwalker… this helped me to get teh desired result…but can i make a proeprty out of it so that i can take these values from webreport…i just tried to create a property but the result is as expected and as below :

(name

of

it

&

“:”

&

(
if

it

<

30

then

“less than 30”

else

if

it

<

60

then

“between 30 and than 60”

else

if

it

<

90

then

“between 60 and 90”

else

“more than 90”
)

of

((now

last report time

of

it
)

/

day))

of

bes computers

E:
The operator “bes computers” is not defined.

can you please guide me as how i can assigbn these value to a poroperty and then extarct it using webreport…

thanks a lot again :slight_smile:

(imported comment written by JasonWalker)

I haven’t done much in Web Reports. I think though that the problem is that Properties are generated from the client. You could use “last report time of client” in Client Relevance…but that’s only going to be reported up to the server when the client reports (which kind of defeats the purpose of finding clients that aren’t reporting).

I think you just got out of my depth in Web Reports though. Anyone else know how to manipulate an existing property (like “Last report time”) and format it in Relevance for Web Reports?

I know if you were doing this in a Dashboard you could use the <?relevance ?> tags, but I don’t know whether that’s available in Web Reports…

(imported comment written by jgstew)

Last report time is based upon when the client last submitted the report, but “now” in session relevance should be based upon the clock of the web reports server or root server since that is the context of which “now” is executed. This is what would allow you to filter clients based upon how long ago they have last reported.

This is also why (now- last report time of client) doesn’t work outside of session relevance since with client relevance, “now” is based upon the clock of the client when it did the evaluation in the past, but not the present.

(imported comment written by JasonWalker)

Oh, and one more thing, there should already be a property for “last report time”. I don’t think you need to create a new property, you just need to format your output based on what the value of the last report time already is.

(imported comment written by MattPeterson)

You would need to create a custom report that includes this information. To do so go to explore data, click custom near the top right, then paste the text below and choose save report. Most of what I’m including below is formatting for the table which makes it look nice and allows you to sort. The highlighted text below is where you would modify the relevance or table headers. I’ve set this to only show computers which haven’t reported in over a day, but this could be easily modified to your likings. You could then have this report sent out on a regular basis if desired.

<head>


    <style type="text/css">


       


      a {


            text-decoration: none;


        }


       


        a:hover {


            color: #FF8000;


            font-weight: bold;


            text-decoration: none;


        }


       


        table {


         margin: 0;


border-collapse: collapse;


            color: #222;


            font: 10pt verdana, geneva, lucida, 'lucida grande', arial, helvetica, sans-serif;


        }


        th {


            font: 10pt verdana, geneva, lucida, 'lucida grande', arial, helvetica, sans-serif;


            color: navy;


            font-weight: bold;


            background-color: #F2F2F2;


            border: 1px solid #cccccc;


            margin: 0;


            padding: 4px 10px 4px 5px;         


            text-align: left;


        }


       


        td {


            color: #222;


            font: 8pt verdana, geneva, lucida, 'lucida grande', arial, helvetica, sans-serif;


            border-bottom: 1px solid #cccccc;


            margin: 0;


            /* padding: 6px 20px 1px 0;  */

padding: 8px 20px 5px 5px;

        }


       


        td.userinput {


            color: #222;


            font: 10pt verdana, geneva, lucida, 'lucida grande', arial, helvetica, sans-serif;


            font-weight: bold;


            border-bottom: 0px;


            margin: 0;


            padding: 6px 20px 1px 0;


        }


       


        td.errormsg {


            color: red;


            font: 10pt verdana, geneva, lucida, 'lucida grande', arial, helvetica, sans-serif;


            font-weight: bold;


            border-bottom: 0px;


            margin: 0;


            padding: 6px 20px 1px 0;


        }


        td.msg {


            color: #747170;


            font: 10pt verdana, geneva, lucida, 'lucida grande', arial, helvetica, sans-serif;


            font-weight: bold;


            border-bottom: 0px;


            margin: 0;


            padding: 6px 20px 1px 0;


        }


       


        h3 {


            font: 10pt verdana, geneva, lucida, 'lucida grande', arial, helvetica, sans-serif;


            background-color: #747170;


            padding: 4px 4px 4px 4px;


            color: white;


            width: 100%;


        }


    </style>


</head>


<body>   


    <div id="resultsDiv">


        <table>
<?Relevance concatenation of trs of ( td of name of it & td of (((year of it as string & "/" & month of it as two digits & "/" & day_of_month of it as two digits) of date (local time zone) of it & " "& (two digit hour of it as string & ":" & two digit minute of it as string & ":" & two digit second of it as string) of time (local time zone) of it) of (last report time of it)) & td of (((now - last report time of it) / day) as string) & td of (((if it < 30 then "less than 30" else if it < 60 then "between 30 and than 60" else if it < 90 then "between 60 and 90" else "more than 90") of ((now - last report time of it) / day)) of it) ) of bes computers whose (now - last report time of it > 1*day) ?>
Computer Name Last Report Time # Days Days Group
    </div>


    <script type="text/javascript">


       


        addEvent(window, "load", init_load);


       


        function init_load()


        {


   stripe('resultsTable', '#fff', '#E6E3E8');

// #E6E3E8, original edf3fe’

         sortables_init();


        }


       


        var SORT_COLUMN_INDEX;


        function sortables_init(){


       


            // Find all tables with class sortable and make them sortable


            if (!document.getElementsByTagName)


                return;


            tbls = document.getElementsByTagName("table");


            for (ti = 0; ti < tbls.length; ti++) {


                thisTbl = tbls[ti];


                if (((' ' + thisTbl.className + ' ').indexOf("sortable") != -1) && (thisTbl.id)) {


                    //initTable(thisTbl.id);


                    ts_makeSortable(thisTbl);


                }


            }


        }


       


        function ts_makeSortable(table){


            if (table.rows && table.rows.length > 0) {


                var firstRow = table.rows[0];


            }


            if (!firstRow)


                return;


           


            // We have a first row: assume it's the header, and make its contents clickable links


            for (var i = 0; i < firstRow.cells.length; i++) {


                var cell = firstRow.cells[i];


                var txt = ts_getInnerText(cell);


                cell.innerHTML = '<a href="#" class="sortheader" ' +


                'onclick="ts_resortTable(this, ' +


                i +


                ');return false;">' +


                txt +


                '<span class="sortarrow">   </span></a>';


            }


        }


       


        function ts_getInnerText(el){


            if (typeof el == "string")


                return el;


            if (typeof el == "undefined") {


                return el


            };


            if (el.innerText)


                return el.innerText; //Not needed but it is faster


            var str = "";


           


            var cs = el.childNodes;


            var l = cs.length;


            for (var i = 0; i < l; i++) {


                switch (cs[i].nodeType) {


                    case 1: //ELEMENT_NODE


                        str += ts_getInnerText(cs[i]);


                        break;


                    case 3: //TEXT_NODE


                        str += cs[i].nodeValue;


                        break;


                }


            }


            return str;


        }


       


        function ts_resortTable(lnk, clid){


            // get the span


            var span;


            for (var ci = 0; ci < lnk.childNodes.length; ci++) {


                if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span')


                    span = lnk.childNodes[ci];


            }


            var spantext = ts_getInnerText(span);


            var td = lnk.parentNode;


            var column = clid || td.cellIndex;


            var table = getParent(td, 'TABLE');


           


            // Work out a type for the column


            if (table.rows.length <= 1)


                return;


            var itm = ts_getInnerText(table.rows[1].cells[column]);


            sortfn = ts_sort_caseinsensitive;


            if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/))


                sortfn = ts_sort_date;


            if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/))


                sortfn = ts_sort_date;


            if (itm.match(/^[ $]/))


                sortfn = ts_sort_currency;


            if (itm.match(/^[\d\.]+$/))


                sortfn = ts_sort_numeric;


            SORT_COLUMN_INDEX = column;


            var firstRow = new Array();


            var newRows = new Array();


            for (i = 0; i < table.rows[0].length; i++) {


                firstRow[i] = table.rows[0][i];


            }


            for (j = 1; j < table.rows.length; j++) {


                newRows[j - 1] = table.rows[j];


            }


            newRows.sort(sortfn);


            if (span.getAttribute("sortdir") == 'down') {


                ARROW = ' <img src="/images/besreports/ENU/maximizebutton1.gif" border="0" height="12" width="15" alt="">';


                newRows.reverse();


                span.setAttribute('sortdir', 'up');


            }


            else {


                ARROW = ' <img src="/images/besreports/ENU/minimizebutton1.gif" border="0" height="12" width="15" alt="">';


                span.setAttribute('sortdir', 'down');


            }


           


            // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones


            // don't do sortbottom rows


            for (i = 0; i < newRows.length; i++) {


                if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1))) {


                    table.tBodies[0].appendChild(newRows[i]);


                    if (i % 2 > 0)


                        newRows[i].className = 'wr_oddRow';


                    else


                        newRows[i].className = 'wr_evenRow';


                }


            }


            // do sortbottom rows only


            for (i = 0; i < newRows.length; i++) {


                if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') != -1))


                    table.tBodies[0].appendChild(newRows[i]);


            }


           


            // Delete any other arrows there may be showing


            var allspans = document.getElementsByTagName("span");


            for (var ci = 0; ci < allspans.length; ci++) {


                if (allspans[ci].className == 'sortarrow') {


                    if (getParent(allspans[ci], "table") == getParent(lnk, "table")) { // in the same table as us?


                        allspans[ci].innerHTML = '   ';


                    }


                }


            }


            // adds up/down arrow to the column header


            span.innerHTML = ARROW;





// Make zebra stripes in table


stripe('resultsTable', '#fff', '#E6E3E8');


        }


       


        function getParent(el, pTagName){


            if (el == null)


                return null;


            else


                if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase()) // Gecko bug, supposed to be uppercase


                    return el;


                else


                    return getParent(el.parentNode, pTagName);


        }


       


        function ts_sort_date(a, b){


            // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX


            aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);


            bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);


            if (aa.length == 10) {


                dt1 = aa.substr(6, 4) + aa.substr(3, 2) + aa.substr(0, 2);


            }


            else {


                yr = aa.substr(6, 2);


                if (parseInt(yr) < 50) {


                    yr = '20' + yr;


                }


                else {


                    yr = '19' + yr;


                }


                dt1 = yr + aa.substr(3, 2) + aa.substr(0, 2);


            }


            if (bb.length == 10) {


                dt2 = bb.substr(6, 4) + bb.substr(3, 2) + bb.substr(0, 2);


            }


            else {


                yr = bb.substr(6, 2);


                if (parseInt(yr) < 50) {


                    yr = '20' + yr;


                }


                else {


                    yr = '19' + yr;


                }


                dt2 = yr + bb.substr(3, 2) + bb.substr(0, 2);


            }


           


            if (dt1 == dt2)


                return 0;


            if (dt1 < dt2)


                return -1;


            return 1;


        }


       


        function ts_sort_currency(a, b){


            aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g, '');


            bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g, '');


            return parseFloat(aa) - parseFloat(bb);


        }


       


        function ts_sort_numeric(a, b){


            aa = parseFloat(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]));


            if (isNaN(aa))


                aa = 0;


            bb = parseFloat(ts_getInnerText(b.cells[SORT_COLUMN_INDEX]));


            if (isNaN(bb))


                bb = 0;


            return aa - bb;


        }


       


        function ts_sort_caseinsensitive(a, b){


            aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).toLowerCase();


            bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).toLowerCase();


            if (aa == bb)


                return 0;


            if (aa < bb)


                return -1;


            return 1;


        }


       


        function ts_sort_default(a, b){


            aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);


            bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);


            if (aa == bb)


                return 0;


            if (aa < bb)


                return -1;


            return 1;


        }


       


        function addEvent(elm, evType, fn, useCapture)// addEvent and removeEvent


        // cross-browser event handling for IE5+,  NS6 and Mozilla


        // By Scott Andrew


        {


            if (elm.addEventListener) {


                elm.addEventListener(evType, fn, useCapture);


                return true;


            }


            else


                if (elm.attachEvent) {


                    var r = elm.attachEvent("on" + evType, fn);


                    return r;


                }


                else {


                    alert("Handler could not be removed");


                }


        }

// this function is needed to work around

// a bug in IE related to element attributes


 function hasClass(obj) {


    var result = false;


    if (obj.getAttributeNode("class") != null) {


        result = obj.getAttributeNode("class").value;


    }


    return result;


 }  





function stripe(id) {





   // the flag we'll use to keep track of


   // whether the current row is odd or even


   var even = false;





   // if arguments are provided to specify the colours


   // of the even & odd rows, then use the them;


   // otherwise use the following defaults:


   var evenColor = arguments[1] ? arguments[1] : "#fff";


   var oddColor = arguments[2] ? arguments[2] : "#eee";





   // obtain a reference to the desired table


   // if no such table exists, abort


   var table = document.getElementById(id);


   if (! table) { return; }


  


   // by definition, tables can have more than one tbody


   // element, so we'll have to get the list of child


   // <tbody>s


   var tbodies = table.getElementsByTagName("tbody");





   // and iterate through them...


   for (var h = 0; h < tbodies.length; h++) {


  


    // find all the <tr> elements...


     var trs = tbodies[h].getElementsByTagName("tr");


    


     // ... and iterate through them


     for (var i = 0; i < trs.length; i++) {





         // get all the cells in this row...


         var tds = trs[i].getElementsByTagName("td");


      


         // and iterate through them...


         for (var j = 0; j < tds.length; j++) {


      


           var mytd = tds[j];


  


             mytd.style.backgroundColor =


               even ? evenColor : oddColor;


 


         }


       // flip from odd to even, or vice-versa


       even =  ! even;


     }


   }


 }


    </script>


</body>

(imported comment written by Darknight)

thanks a trillion mattpeterson and JasonWalker for your extended help in making me understand the session relevance and use of custom webreport…

i have already created a report as attached which is not using the session relevance and in that report i want to add one more filed/column with the name ‘agent scan date’ which will give output on the basis if logic which i have posted in my earlier post.

so could you please let me know whether the below relevance which i have created is correct and will be able to give me the expected results :

if ((0 <= ((now - (apparent registration server time)) / day) AND (((now - (apparent registration server time)) / day) <= 30)) then (“Less Than 30 Days”) else if ((30 < (((now - (apparent registration server time)) / day) AND (((now - (apparent registration server time)) / day) <= 60)) then (“Greater than 30 Days”) else if ((60 < ((now - (apparent registration server time)) / day) AND (((now - (apparent registration server time)) / day) <= 90)) then (“Greater Than 60 Days”) else if (((now - (apparent registration server time)) / day) >= 90) then (“Greater Than 90 Days”) else (“error in evaluating”)

Basically i have created a analysis which contains different hadrware related properties like osrelease , osversion, disk size,number of disks etc… and i want to know what was the last time this data got fetched from particular machine ( in days format) .

For example :

This analysis contains propeties which are getting evaluated after every 15 days.

on server A analysis ran for very first time on say 1st of june 2014 and therfore the value which i am expecting will be 0 days as the data which was scanned and captured in the report is the latest one but if the same analysis is trying to fetch the data from the same server on 15th June 2014 but due to some reason this server has not reported for last 14 days , so the value which i am going to get through report this time will be 14 days as the data collected this time from the analysis will be 14 days old. so on and so forth.

Please let me know whether the above logic will be helpful in this case or is there any other logic which i can apply to get the result.Maybe something like ( current time of TEM server - current time of endpoint ) / days or ( Current time of IEM server - last report time of endpoint) / days.

Kindly advise.

(imported comment written by Darknight)

Can someone please provide a hint or help