What is the best way to log current users in a ColdFusion application?

traport
traport used Ask the Experts™
on
I need to display a list of users currently logged into my system. Is there a more reliable way than to just log the users in a table when they log in? If I use this, then I won't know if the person is actively in the system (they may have logged in and then closed their browser) and they might not use the logout functionality in order to update the log of users in the system. I'm assuming there's a logical way but I don't even know where to start. Would love to hear your thoughts!
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Most Valuable Expert 2015

Commented:
Use the OnSessionEnd event to run an UPDATE on your table. Then a user's status is always updated, even if they don't use your logout feature.

<cffunction name="onSessionEnd" returnType="void">
    <cfargument name="SessionScope" required=True/>
    <cfargument name="ApplicationScope" required=False/>
    <cfset var cleanup = "">
    <cfquery name="cleanup" ....>
            run your update ...
    </cfquery>
</cffunction>


Most Valuable Expert 2015

Commented:
Also, there are other methods for tracking "on line" status.  For example you could store a list of users in an application variable instead.  Just keep in mind application variables are temporary. ie When the application ends, the information disappears.  Using a database table is better if you want to maintain history.

Here's how I do this...

 I have a table "usersessions"  (you could use your user table as well)  

 on Login, add a record to the userSessions table with the dateTime of login, store the primary key of that table in a session variable

 then in your onRequestStart,  update a column in the userSessions table lastActivityDate to the current date/time.

 in your onSessionEnd function, you can delete the record (or mark it as closed if you wish to keep around the user's history for a while)

 This will give you their login date/time, the last time they refreshed a page, the amount of time they have been connected.   The combination of these three will give you a pretty good idea if the user is active or if they went to lunch :)

Announcing the Winners!

The results are in for the 15th Annual Expert Awards! Congratulations to the winners, and thank you to everyone who participated in the nominations. We are so grateful for the valuable contributions experts make on a daily basis. Click to read more about this year’s recipients!

Most Valuable Expert 2015

Commented:
>> then in your onRequestStart,  update a column in the userSessions table
>> lastActivityDate to the current date/time.

Nice one. I like that idea.

Thanks!

Side note - you don't need to wait until the user logs in to create the userSessions record.  I actually create it onSessionStart.   That way you can see who is online even if they are not logged in.   When/If the person logs in, you just update the userSessions table with their login ID, now that gives them an identity.  Before they login, you know they are there, you just don't know who they are yet.
Most Valuable Expert 2015

Commented:
Oh yeah, then you can list anonymous users like "userxxxxx".  I like it!

@traport - IMO, go with gdemaria's approach.  Very solid.

Author

Commented:
Well, I have a question... While I was searching for solutions and before I saw your answers I found this approach

Link to solution detailed below

 
<!---  
If application.sessionTracker is not defined, create it 
and set its initial value to an empty structure
--->    
<cfparam name="application.sessionTracker" 
 default="#StructNew()#">

<!---  
When a user logs in, a session variable, 
session.login_id, is created. So, If we have 
a logged in user then add an entry in the 
sessionTracker with a key of session.login_id 
and a value of the current date/time. The 
time indicates when the last time the user had 
an activity in the application.
--->    
<cfif isDefined ("session.login_id")>
    <cfset dummy = structInsert( 
         application.sessionTracker,
         session.login_id, 
         now(), true)>
</cfif>

Open in new window



 
<cfoutput> 
<h3>Live Session Tracker Report</h3> 
<table> 
<tr> 
    <td><b>Login ID</b></td> 
    <td><b>Session Status</b></td> 
</tr> 
<cfloop collection=#application.sessionTracker# 
                  item="auser"> 
    <cfset onlineSince = structfind(
                  application.sessionTracker, auser)> 
    <!--- 
    Assuming that your session timeout is 60 minutes 
    ---> 
    <cfif dateCompare(onlinesince+60, now()) eq 1> 
        <!--- 
        User's last activity lies within session 
             timeout, so his/her session is active 
        ---> 
        <cfset inactiveSince = 
                     datediff("n", onlineSince, Now())> 
        <tr> 
            <td>#aUser#"</td> 
            <td> 
                inactive for <b>#inactiveSince#</b> mins 
            </td> 
        </tr> 
    <cfelse> 
        <!--- 
        User's session has timed out, 
        so we can delete it from the structure 
        ---> 
        <cfset structDelete(
                     application.sessionTracker, aUser)> 
    </cfif> 
</cfloop> 
</table> 
<cfif StructCount(application.SessionTracker) gt 1>
    #StructCount(application.SessionTracker)# 
        Users online. 
</cfif>
</cfoutput>

Open in new window


What would be wrong with this approach?


Most Valuable Expert 2015

Commented:
>> What would be wrong with this approach?

I didn't review it in detail. But like I mentioned before http:#a36330127 there are other approaches than db storage. application variables are fine for a quick and simple tracker. The main difference is application variables are volatile/temporary.  Once they expire the information is gone. If you want to support history or tracking use a db table. Otherwise, application variables may do the trick.
Most Valuable Expert 2015

Commented:
>> I didn't review it in detail.

ie Don't take it as an endorsement. I've barely skimmed the code.
> What would be wrong with this approach

The database is a more powerful and efficient place to store information.   Using the database you can easily pull reports from the active user list joining the information with the user table to see additional information (user's name, login, invoice history, anything you like).   The approach you showed limits you.

Why not use the database approach?

Some people are under the misunconception that the database would be slower and more resource intensive, it's just the opposite.  Doing this all in CF would be more of a drain on system resources (as agx also mentions).

I built a who's online widget awhile ago using some of the techniques above if you've like to have a look.

http://sidfishes.wordpress.com/2009/01/09/a-coldfusion-whos-online-widget/

Author

Commented:
Thanks everyone for the help!

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial