Time on page calculated only for specific segment in Adobe Analytics - adobe-analytics

Goal
I would like to see what is the time on page for user who is logged in. Eliminate from reports time, while user was not logged in.
To have ability to distinguish between time on page while user is not logged in and time on page while he is logged in.
Setup
Let's say we have:
Traffic variable User logged in as a prop1 where is true or false.
Traffic variable Time from previous event as a prop2 in seconds
eVar1 duplicating prop1 | expire after event5
eVar2 duplicating prop2 | expire after event5
event4 - User logged in
event5 - User logged out
Time between events
From an article about measuring time between events (https://experienceleaguecommunities.adobe.com/t5/adobe-analytics-questions/calculate-time-between-success-events/qaq-p/302787)
if (s.events && (s.events + ",").indexOf("event4,") > -1) {
s.prop2 = "start"
}
if (s.events && (s.events + ",").indexOf("event5,") > -1) {
s.prop2 = "stop"
}
s.prop2 = s.getTimeToComplete(s.prop2, "TTC", 0);
s.getTimeToComplete = new Function("v", "cn", "e", "var s=this,d=new Date,x=d,k;if(!s.ttcr){e=e?e:0;if(v=='start'||v=='stop')s.ttcr=1;x.setTime(x.getTime()+e* 86400000);if(v=='start'){s.c_w(cn,d.getTime(),e?x:0);return '';}if(v=='stop'){k=s.c_r(cn);if(!s.c_w(cn,'',d)||!k)return '';v=(d.getTime()-k)/1000;var td=86400,th=3600,tm=60,r=5,u,un;if(v>td){u=td;un='days';}else if(v>th){u=th;un='hours';}else if(v>tm){r=2;u=tm;un='minutes';}else{r=.2;u=1;un='seconds';}v=v*r/u;return (Math.round(v)/r)+' '+un;}}return '';");
Time spent overview
From adobe docs (https://docs.adobe.com/content/help/en/analytics/components/metrics/time-spent.html)
A “sequence” is a consecutive set of hits where a given variable
contains the same value (whether by being set, spread forward, or
persisted). For example, prop1 “A” has two sequences: hits 1 & 2 and
hit 6. Values on the last hit of the visit do not start a new sequence
because the last hit has no time spent. Average time spent on site
uses sequences in the denominator.
So I guess I will uses prop1 as a denominator for logged in user state to count time between event in prop2 properly.
Problem
I am not pretty sure, If this approach is enough to correctly measure time spent only while user is logged in. I would appreciate some hints, how to set up eVars correctly or if I understand sequence denominator correctly.
I also set up eVars with terminating event5, but I am not sure, If this leads to desired behavior.
If you also solve this problem before, please can you lead me, how you define your segment or condition in reports.

GetTimeBetweenEvents plugin should do a job. However, it seems like it was rewritten, I have found in documentation example calls also using Launch plugins extension:
https://docs.adobe.com/content/help/en/analytics/implementation/vars/plugins/gettimebetweenevents.html
From Adobe documentation
Install the plug-in using AppMeasurement Copy and paste the following
code anywhere in the AppMeasurement file after the Analytics tracking
object is instantiated (using s_gi ). Preserving comments and version
numbers of the code in your implementation helps Adobe with
troubleshooting any potential issues.
/******************************************* BEGIN CODE TO DEPLOY *******************************************/
/* Adobe Consulting Plugin: getTimeBetweenEvents v2.1 (Requires formatTime and inList plug-ins) */
s.getTimeBetweenEvents=function(ste,rt,stp,res,cn,etd,fmt,bml,rte){var s=this;if("string"===typeof ste&&"undefined"!==typeof rt&&"string"===typeof stp&&"undefined"!==typeof res){cn=cn?cn:"s_tbe";etd=isNaN(etd)?1:Number(etd);var f=!1,g=!1,n=!1, p=ste.split(","),q=stp.split(",");rte=rte?rte.split(","):[];for(var h=s.c_r(cn),k,v=new Date,r=v.getTime(),c=new Date,a=0; a<rte.length;++a)s.inList(s.events,rte[a])&&(n=!0);c.setTime(c.getTime()+864E5*etd);for(a=0;a<p.length&&!f&&(f=s.inList(s.events,p[a]),!0!==f);++a);for(a=0;a<q.length&&!g&&(g=s.inList(s.events,q[a]),!0!==g);++a);1===p.length&&1===q.length&&ste===stp&&f&&g?(h&&(k=(r-h)/1E3),s.c_w(cn,r,etd?c:0)):(!f||1!=rt&&h||s.c_w(cn,r,etd?c:0),g&&h&&(k=(v.getTime()-h)/1E3,!0===res&&(n=!0)));!0===n&&(c.setDate( c.getDate()-1),s.c_w(cn,"",c));return k?s.formatTime(k,fmt,bml):""}};
/* Adobe Consulting Plugin: formatTime v1.1 (Requires inList plug-in) */
s.formatTime=function(ns,tf,bml){var s=this;if(!("undefined"===typeof ns||isNaN(ns)||0>Number(ns))){if("string"===typeof tf&&"d"===tf||("string"!==typeof tf||!s.inList("h,m,s",tf))&&86400<=ns){tf=86400;var d="days";bml=isNaN(bml)?1:tf/(bml*tf)} else"string"===typeof tf&&"h"===tf||("string"!==typeof tf||!s.inList("m,s",tf))&&3600<=ns?(tf=3600,d="hours", bml=isNaN(bml)?4: tf/(bml*tf)):"string"===typeof tf&&"m"===tf||("string"!==typeof tf||!s.inList("s",tf))&&60<=ns?(tf=60,d="minutes",bml=isNaN(bml)?2: tf/(bml*tf)):(tf=1,d="seconds",bml=isNaN(bml)?.2:tf/bml);ns=Math.round(ns*bml/tf)/bml+" "+d;0===ns.indexOf("1 ")&&(ns=ns.substring(0,ns.length-1));return ns}};
/* Adobe Consulting Plugin: inList v2.1 */
s.inList=function(lv,vtc,d,cc){if("string"!==typeof vtc)return!1;if("string"===typeof lv)lv=lv.split(d||",");else if("object"!== typeof lv)return!1;d=0;for(var e=lv.length;d<e;d++)if(1==cc&&vtc===lv[d]||vtc.toLowerCase()===lv[d].toLowerCase())return!0;return!1};
/******************************************** END CODE TO DEPLOY ********************************************/
Then your eVar may looks like:
s.eVar1 = s.getTimeBetweenEvents("event1", true, "event2", true, "", 0, "s", 2, "event3");

Related

New Relic alert when application stop

I have an application deployed on PCF and have a new relic service binded to it. In new relic I want to get an alert when my application is stopped . I don't know whether it is possible or not. If it is possible can someone tell me how?
Edit: I don't have access to New Relic Infrastructure
Although an 'app not reporting' alert condition is not built into New Relic Alerts, it's possible to rig one using NRQL alerts. Here are the steps:
Go to New Relic Alerts and begin creating a NRQL alert condition:
NRQL alert conditions
Query your app with:
SELECT count(*) FROM Transaction WHERE appName = 'foo'
Set your threshold to :
Static
sum of query results is below x
at least once in y minutes
The query runs once per minute. If the app stops reporting then count will turn the null values into 0 and then we sum them. When the number goes below whatever your threshold is then you get a notification. I recommend using the preview graph to determine how low you want your transactions to get before receiving a notification. Here's some good information:
Relic Solution: NRQL alerting with “sum of the query results”
Basically you need to create a NewRelic Alert with conditions that check if application available, Specially you can use Host not reporting alert condition
The Host not reporting event triggers when data from the Infrastructure agent does not reach the New Relic collector within the time frame you specify.
You could do something like this:
// ...
aggregation_method = "cadence" // Use cadence for process monitoring otherwise it might not alert
// ...
nrql {
// Limitation: only works for processes with ONE instance; otherwise use just uniqueCount() and set a LoS (loss of signal)
query = "SELECT filter(uniqueCount(hostname), WHERE processDisplayName LIKE 'cdpmgr') OR -1 FROM ProcessSample WHERE GENERIC_CONDITIONS FACET hostname, entityGuid as 'entity.guid'"
}
critical {
operator = "below"
threshold = 0
threshold_duration = 5*60
threshold_occurrences = "ALL"
}
Previous solution - turned out it is not that robust:
// ...
critical {
operator = "below"
threshold = 0.0001
threshold_duration = 600
threshold_occurrences = "ALL"
}
nrql {
query = "SELECT percentage(uniqueCount(entityAndPid), WHERE commandLine LIKE 'yourExecutable.exe') FROM ProcessSample FACET hostname"
}
This will calculate the fraction your process has against all other processes.
If the process is not running the percentage will turn to 0. If you have a system running a vast amount of processes it could fall below 0.0001 but this is very unprobable.
The advantage here is that you can still have an active alert even if the process slips out of your current time alert window after it stopped. Like this you prevent the alert from auto-recovering (compared to just filtering with WHERE).

Change request.comment-value?

I use different kinds of stop losses and would like to be notified (SendNotification()) about which kind of stop loss was hit upon trade exit.
Let's say I entered a trade by...
request.action = TRADE_ACTION_DEAL;
request.symbol = pSymbol;
request.type = pType;
request.sl = pStop;
request.tp = pProfit;
request.comment = pComment;
request.volume = pVolume;
request.price = SymbolInfoDouble(pSymbol,SYMBOL_ASK);
request.price = SymbolInfoDouble(pSymbol,SYMBOL_BID)
OrderSend(request,result);
I would now like to have the request.comment changed by the last stop loss like so:
request.action = TRADE_ACTION_SLTP;
request.symbol = pSymbol;
request.sl = pStop;
request.tp = pProfit;
request.comment = "Fixed SL";
PositionSelect(_Symbol);
request.order = PositionGetInteger(POSITION_IDENTIFIER);
OrderSend(request,result);
Unfortunately the second block of code does not change the first request.comment = pComment; though (instead the new comment is [sl 1.19724]).
Is it possible to change the comment via TRADE_ACTION_SLTP? What am I doing wrong?
Thank you!
I would now like to have the request.comment changed
There was never a way to do this in MQL4/5 trading platforms
Sad, but true.
The core-functionality was always focused on engineering a fast, reliable soft-real-time ( providing still just a best-effort scheduling alongside the stream of externally injected FxMarket-Event-Flow ), so bear with the product as-is.
Plus, there was always one more degree-of-uncertainty, the Broker-side automation was almost free for modifying the .comment-part of the Trade-position, so even if your OrderSend() was explicit on what ought be stored there, the result was unsure and the Broker-side could ( whenever, be it immediately or at any later stage ) change this field outside of any control ( which was not left on your side ), so the only semi-UUID# keys could have been placed into the .magic ( and your local-side application code always had to do all the job via some key:value storage extension to the otherwise uncertain Broker-side content.
Even the Trade number ( ID, ticket ) identifier is not always a persistent key and may change under some Trade management operations, so be indeed very carefull, before deciding your way.
like to be notified ( SendNotification() ) about which kind of stop loss was hit upon trade exit.
Doable, yet one will need to build all the middleware-logic on one's own :
The wish is clear and doable. Given a proper layer of middleware-logic will get built, one can enjoy whatever such automation.
Having built things like an augmented-visual-trading, remote AI/ML-quant-predictors or real-time fully-adaptive non-blocking GUI-quant-tools augmentations ( your trader gets online graphical visual aids inside GUI, automatically overlaid over other EA + Indicator tools on the GUI-surface, fully click-and-modify interactive / adaptive for fast visually augmented discretionary modifications of the traded asset management ), so only one's imagination and resources available are one's limit here.
Yet, one has to respect the published platform limits - the same as OrderModify() does not provide any means for the wish above, the add-on traded assets customer-specific reporting on position terminations is to be assembled by one's own initiative, as the platform does not provide ( for obvious reasons noted above ) any tools, relevant for such non-core activity.

getAdGroupBidLandscape returning no campaigns found

I'm trying to use the Google AdWords bid simulator system to try and get some insights out of the AdWords bid simulator. More specifically I'm using the AdGroupBidLandscape() functionality, but it's returning 'No Campaigns Found', but we definitely have campaigns where the Bid Simulator tool works through the AdWords web page interface, so I'm a bit confused. Here is the code I'm running, and yes I know I'm only retrieving a single field - I'm just trying to keep things as simple as possible.
from googleads import adwords
import logging
import time
CHUNK_SIZE = 16 * 1024
PAGE_SIZE = 100
logging.basicConfig(level=logging.INFO)
logging.getLogger('suds.transport').setLevel(logging.DEBUG)
adwords_client = adwords.AdWordsClient.LoadFromStorage()
dataService = adwords_client.GetService('DataService', version='v201710')
offset = 0
selector = {'fields':['Bid'], #'impressions', 'promotedImpressions', 'requiredBudget', 'bidModifier', 'totalLocalImpressions', 'totalLocalClicks', 'totalLocalCost', 'totalLocalPromotedImpressions'],
'paging': {
'startIndex': str(offset),
'numberResults': str(PAGE_SIZE)
}
}
more_pages = True
while more_pages:
page = dataService.getAdGroupBidLandscape(selector)
# Display results.
if 'entries' in page:
for campaign in page['entries']:
print ('Campaign with id "%s", name "%s", and status "%s" was '
'found.' % (campaign['id'], campaign['name'],
campaign['status']))
else:
print 'No campaigns were found.'
offset += PAGE_SIZE
selector['paging']['startIndex'] = str(offset)
more_pages = offset < int(page['totalNumEntries'])
time.sleep(1)
We have several different accounts attachd to AdWords. My account is the only one that has developer API access, so I sort of wonder if the problem is that my account isn't the primary account associated with the campaigns- I just have one of the few administrator accounts. Can anyone provide some insights about this for me?
Thanks,
Brad
The solution I found to this problem was to add a predicate to the selector specifying a particular CampaignId. While that doesn't make any sense to me that it would fix it, because it should really just be filtering the data with that if I understand things correctly, it seems to have. I don't have a good explanation for that, but I thought someone else might find this useful. If I come to realize this wasn't the fix to the problem I had, I will come back and update this answer.

Posting date issue due to time zones and the use of SystemDateGet()

Summary
We are experiencing a problem where the systemDateGet() function is returning the
AOS wher the local date is required when determining the date for posting purposes.
Details
We have branches around the world, both sides of the international date line, with
users connecting to local terminal servers with the appropriate time zone settings
for the user's branch.
Each branch is associated with a different company, which has been configured with
the correct time zone.
We run a single AOS with the time zone setting set for the head office. There is
not an option to introduce additional AOS's.
The SystemDateGet() function is returning the AOS date as the user is not changing
their Axapta session date.
A number of system fields in the database related to posting dates are DATE based and
not UTCDATETIME based.
We are running AX2009 SP1 RU7.
Kernel version 5.0.1500.4570
Application version 5.0.1500.4570
Localization version: Brazil, China, Japan, Thailand, India
I am aware that the SystemDateGet() function was designed to return the AOS date unless
the user changes their session date in which case that date is returned.
Each user has the appropriate time zone setting in there user profile.
Problem
One example of the problem is when a user attempts to post a journal involving financial
transactions, where the ledger period is checked to see if it is open. For example,
the user is in England attempting to post a journal at 3:00pm on the 30st of November, local
time, the standard Axapta code uses the systemDateGet() function to determine the date to use
in the validation (determining if the period is open). In our case, the AOS is based in
Brisbane Australia and the systemDateGet() function is returning the 1st of December
(local time 1:00am on the 1st of December).
Another example of the problem is where an invoice is posted in the United States on a Friday
and the day of the week where the AOS is situated is a Saturday. We need the system to
record the local date.
Question
Besides rewriting all system code involving systemDateGet(), over 2000 entities, is there
any other options that can be used to get around the problem of getting the correct local
date?
Solution limitations.
In the example given above of the ledger period being closed, it is not possible from a
business practices standpoint to open the next period before end of month processing
has been completed.
There is currently no option for the purchase of additional AOS's.
Create a function in the Global class:
static date systemDateGetLocal()
{
return DateTimeUtil::date(DateTimeUtil::applyTimeZoneOffset(DateTimeUtil::utcNow(), DateTimeUtil::getUserPreferredTimeZone()));
}
Then in Info.watchDog() do a:
systemDateSet(systemDateGetLocal());
This may only be a partial solution, the watchDog is executed on the client side only.
Here is a quick update. Let me know if there are any issues or situations that need to be addressed.
USING LOCAL TIME
Introduction:
The following is a work in progress update, as the solution has yet to be fully tested in all situations.
Problem:
If the user has a different time zone to the AOS, the timeNow() and systemDateGet() functions are returning the AOS details when the local date time is required.
Clarifiers:
When the local date time is changed within Axapta, the systemDateGet() function will return the local date, however the timeNow() function still returns the AOS time.
Coding changes:
A number of coding changes have been made to handle a number of different situations. Comments will be added where an explanation may be required.
The brackets were changed to { and } to allow this to be posted.
CLASS:GLOBAL
One requirement I was given was to allow the system to handle multiple sites within a company that may have different time zones. Presently this functionality is not required.
static server void setSessionDateTime(
inventSiteId inventSiteId = '',
utcDateTime reference = dateTimeUtil::utcNow())
{
str sql;
sqlStatementExecutePermission perm;
connection conn = new UserConnection();
timeZone timeZone;
int ret;
;
if (inventSiteId)
{
timeZone = inventSite::find(inventSiteId).Timezone;
}
else
{
timeZone = dateTimeUtil::getCompanyTimeZone();
}
//This is to get around the kernel validation of changing timezones
//when the user has more than one session open.
sql = strfmt("Update userInfo set preferredTimeZone = %1 where userInfo.id = '%2'", enum2int(timeZone), curUserId());
perm = new SQLStatementExecutePermission(sql);
perm.assert();
ret = conn.createStatement().executeUpdate(sql);
dateTimeUtil::setUserPreferredTimeZone(timeZone);
dateTimeUtil::setSystemDateTime(reference);
CodeAccessPermission::revertAssert();
}
static int localTime()
{
utcDateTime tmp;
;
setSessionDateTime();
tmp = dateTimeUtil::applyTimeZoneOffset( dateTimeUtil::utcNow(), dateTimeUtil::getCompanyTimeZone());
return dateTimeUtil::time(tmp);
}
The following method was implemented as a cross check to ensure that systemDateGet() returns the expected value.
static date localDate()
{
utcDateTime tmp;
;
setSessionDateTime();
tmp = dateTimeUtil::applyTimeZoneOffset( dateTimeUtil::utcNow(), dateTimeUtil::getCompanyTimeZone());
return dateTimeUtil::date(tmp);
}
CLASS:APPLICATION
Modify the method setDefaultCompany. Add the line setSessionDateTime(); directly after the super call. This is to allow the time to change when the user changes company (another requirement I was given).
CLASS:INFO
So that the system uses the correct date/time from the start of the session.
void startupPost()
{
;
setSessionDateTime();
}
Modify the method canViewAlertInbox() adding the line setSessionDateTime(); as the first line. This is to handle if the user has multiple forms open for different companies.
Localization dependent changes:
Depending on your service pack and localizations, you will need to change a function of objects to use the localTime() function, replacing timeNow(). IMPORTANT NOTE: Do not change the class BatchRun to use the new localTime function as this will stop it working correctly.
In our system there were around 260 instances that could be changed. If you do not use all modules and localizations the actual number of lines you need to change will be less.
Final note:
There are a number of today() calls in the code. I have not yet gone through each line to ensure it is coded correctly, i.e. using today() instead of systemDateGet().
Known issues:
I have come across a situation where the timezone change function did not work completely as expected. This was when one session was doing a database synchronisation and another session was opened in a different company. As normal users will never be able to do this, I have not spent much time on its solution at this stage. It is something I do intend to resolve.

Ad Asp.Net Changing Passwords

We're using ASP.NET MVC and AdMembership provider for login, and for various reasons had to implement our own "Change Password on next Login" functionality.
We also have a nist requirement of not allowing more than one change per 24 hours. so it's set up that way in AD.
What we need is to Ignore that one requirement when resetting a password to default, we want the student to be forced to change the password on the next logon, even if it's before 24 hours.
here is my stab at it. Basically I want to change the PwdLastSet property to a value more than 24 hours old after we reset the password.
if ( bSetToDefault )
{
var adDate = userToActOn.ADEntry.Properties[ "PwdLastSet" ][ 0 ];
DateTime passwordLastSet = DateTime.FromFileTime( ( Int64 ) adDate );
passwordLastSet = System.DateTime.Now.AddHours( -25 );
long filetime = passwordLastSet.ToFileTimeUtc();
userToActOn.ADEntry.Properties[ "PwdLastSet" ][ 0 ] = filetime;
}
But I keep getting null back even when I know the users password has been changed.
anyone got any hints or suggestions? Am I looking in the wrong property?
hmm this attribute is replicated so should always be available.
Try the command line script to see if it shows up:
http://www.rlmueller.net/PwdLastChanged.htm
Its possible because its a 64bit date and not doing a conversion? Try the script though and see if it works. if it does, then look at the Integer8Date procedure in it for your date conversion.
If you use System.DirectoryServices.AccountManagement then there is an exposed method for the User Principal to expire the password immediately. So it will be as easy as calling it like such oUserPrincipal.ExpirePasswordNow(); for more info about using it please see this article.

Resources