Developing a Journal Snippet Dynamic Application

Download this manual as a PDF file

This example describes the development of a Journal Snippet Dynamic Application that collects data from ScienceLogic access logs. Each collected journal entry contains information about a single user session in a SL1 system. This example demonstrates how to use available variables, create, populate, and update journal entries, and how to report collection problems.

This example Dynamic Application is for demonstration purposes only. The data collected by this Dynamic Application is already available in SL1 in the Access Sessions page (System > Monitor > Access Logs).

Use the following menu options to navigate the SL1 user interface:

  • To view a pop-out list of menu options, click the menu icon ().
  • To view a page containing all of the menu options, click the Advanced menu icon ().

Requirements

The Dynamic Application developed in this example has the following requirements:

  • The snippet must run once a minute.
  • The snippet must use a MySQL credential to collect data from the following fields in the master_access.access_log table in a ScienceLogic database:
    • session_id. The unique key SL1 uses to identify a user session. The Dynamic Application must use this value as the key for each journal entry.
    • state. The state of the user session in the SL1 system. The Dynamic Application must use this value as the state for each journal entry, using the following mapping:
      • 0. Represents the "Logged Out" state in SL1. Must map to the journal entry state "Closed".
      • 2. Represents the "Logged In" state in SL1. Must map to the journal entry state "Open".
      • 3. Represents the "Expired" state in SL1. Must map to the journal entry state "Abandoned".

    • user. The ScienceLogic username for the user session. The Dynamic Application must store this value in a collection object for every journal entry.
    • login_time. The time that the user session started. The Dynamic Application must store this value in a collection object for every journal entry.
    • logout_time. The time that the user session ended. The Dynamic Application must store this value in a collection object for every abandoned or closed journal entry.
  • For each collection period, the snippet must query the master_access.access_log table for all user sessions that have started since the previous collection period. If the time of the previous collection period is unknown, the snippet must query the master_access.access_log table for all user sessions that have started in the last 60 seconds. The new entries must be stored in a new journal entry, with information stored for all available collection objects.
  • For each collection period, the snippet must determine which existing journal entries are still open, query the master_access.access_log table for those user sessions, and abandon or close the journal entry if the user session is in an expired or logged out state.
  • If a query on the master_access.access_log table for an existing journal entry indicates that information about the user session is no longer in the table, the journal entry must be set to the Error state.
  • The snippet must handle the following potential exceptions:
    • If the aligned credential is not a MySQL Database credential, the snippet must report a missed poll and not attempt collection.
    • If SL1 cannot connect to the database , the snippet must report a missed poll and not attempt collection.
    • If a serialization or deserialization exception occurs in meta data storage/retrieval, the snippet must generate a minor event, but not report a missed poll.
    • If an error occurs when querying for new user sessions and an error occurs when querying for existing user sessions, the snippet must report a missed poll.
    • If an error occurs when querying for new user sessions, but querying for existing user sessions is successful, the snippet must generate a minor event, but not report a missed poll.
    • If querying for new user sessions is successful, but an error occurs when querying for existing user sessions, the snippet must generate a minor event, but not report a missed poll.

Creating the Dynamic Application

To create this example Dynamic Application, perform the following steps:

  • Go to the Dynamic Applications Manager page (System > Manage > Dynamic Applications).
  • Click the Actions button, then select Create New Dynamic Application. The Create New Application page is displayed.
  • Supply values in the following fields:
    • Application Name. The name of the Dynamic Application. This example is called "Snippet Journal Example".
    • Application Type. This example is a Snippet Journal. Select Snippet Journal in this field.
    • Poll Frequency. To meet requirement one, select Every 1 Minute in this field.
  • This example does not have specific requirements for the other settings defined in this page. You can leave the remaining fields set to the default values.
  • Click the Save button.

Because collection objects are assigned a specific snippet, you must create the container for the snippet code before creating the collection objects for this Dynamic Application. To create a container for the snippet code, perform the following steps:

  • Click the Snippets tab.
  • Supply values in the following fields:
    • Snippet Name. The name of the snippet. The snippet in this example is called "Collect Login Data".
    • Active State. To ensure that the snippet code is run by SL1, select Enabled in this field.
    • Snippet Code. Leave this field blank. You will add the snippet code later in this example.
  • Click the Save button.

Creating the Collection Objects

To meet requirement two, this Dynamic Application must have three collection objects: username, login time, and logout time. Each journal entry will have a value stored for each of these collection objects. To create the collection objects for this Dynamic Application, perform the following steps:

  • Click the Collections tab in the Dynamic Application Editor pane.
  • Supply values in the following fields to create the username object:
    • Object Name. The name of the collection object. Enter "Username" in this field.
    • Variable Name. The name of the variable the snippet will use to store values for this collection object. Enter "Username" in this field.
    • Class Type. The collected values for the username collection object will be text strings. Select 22 Journal Character in this field.
    • Snippet. There is only one snippet for this Dynamic Application. Select Collect Login Data in this field.
  • Click the Save button, then click the Reset button to clear the values you entered.
  • Repeat steps two and three for the login time collection object using the following values:
    • Object Name. Enter "Login Time".
    • Variable Name. Enter "Login".
    • Class Type. Select 30 Journal Date & Time.
    • Snippet. Select Collect Login Data.
  • Repeat steps two and three for the logout time collection object using the following values:
    • Object Name. Enter "Logout Time".
    • Variable Name. Enter "Logout".
    • Class Type. Select 30 Journal Date & Time.
    • Snippet. Select Collect Login Data.

Snippet Code

After creating the Dynamic Application and the collection objects, you must write the snippet code. This section walks through all the snippet code used in this example.

The initial section of snippet code imports the MySQLdb module, then initializes variables used to track collection problems:

import MySQLdb

COLLECTION_PROBLEM = False

create_error = False

update_error = False

The following Boolean values are used to track collection problems:

  • COLLECTION_PROBLEM. The variable used to tell SL1 whether a missed poll has occurred. At the start of execution, this value is "True". The snippet initially changes this value to False (collection was successful), and will later change the value back to True if an exception (as described in requirement six) occurs.
  • create_error. The snippet will use this variable to track whether there was a query error when collecting new journal entries. The snippet initially sets this variable to "False" (no error). Before the snippet completes, this variable will be used to determine how to report errors (as described in requirement six).
  • update_error. The snippet will use this variable to track whether there was a query error when collecting existing journal entries. The snippet initially sets this variable to "False" (no error). Before the snippet completes, this variable will be used to determine how to report errors (as described in requirement six).

The snippet will use the Dynamic Application metadata functions to store the date and time of the last successful query for new journal entries. The next section of code retrieves the stored metadata in a TRY/EXCEPT block:

try:

meta = get_app_instance_meta_data()

except DeserializationError as e:

INTERNAL_ALERTS.append((519, "Could not deserialize stored meta data for did:%s, app id:%s, error: %s" % (app_id, did, e)))

 

To meet requirement six, if a deserialization error occurs, the snippet generates an internal alert using alert id 519 (snippet exception). Alert ID 519 generates a minor event. To meet requirement three, the snippet will continue with collection if a deserialization error occurs, but will query for all new user sessions from the last 60 seconds.

The snippet outputs the credential and collection object information passed in by SL1:

logger.debug("Credential: %s" % (cred_details,))

logger.debug("Collection objects: %s" % (collection_objects,))

If the snippet encounters problems, this information might be useful when diagnosing the issue.

To meet the first item in requirement six, the snippet checks the credential passed in by SL1:

if cred_details['cred_type'] != 2:

COLLECTION_PROBLEM = True

PROBLEM_STR = "Database credential not aligned"

else:

As described in the Performance and Configuration Snippets section, the 'cred_type' key in the cred_details dictionary contains the type of credential. The snippet checks that the credential is of the correct type, '2' (database). If the credential is not for a database, the snippet sets COLLECTION_PROBLEM to "True" to report a missed poll, and sets the PROBLEM_STR to an appropriate error message. If this condition occurs, SL1 will generate a minor event that contains the error message in PROBLEM_STR. If the credential is incorrect, the snippet must finish execution without attempting to collect data; therefore, the remainder of the snippet code is inside the ELSE block.

Similar to the test for the credential type, the snippet attempts to create a MySQL connection using the credential and continues execution only if no exception occurs. The remainder of the snippet code is inside the IF block:

try:

conn = MySQLdb.connect(user=cred_details['cred_user'], passwd=cred_details['cred_pwd'], host=cred_details['cred_host'], port=cred_details['cred_port'])

cur = conn.cursor()

except MySQLdb.Error, e:

COLLECTION_PROBLEM = True

PROBLEM_STR = "Database connection error: %s: %s" % (e.args[0], e.args[1])

 

if COLLECTION_PROBLEM == False:

 

If an exception occurs, the snippet sets COLLECTION_PROBLEM to "True" to meet requirement six. When writing a snippet, you must use TRY/EXCEPT blocks around any calls that might cause an exception; if an exception occurs outside of a TRY/EXCEPT block, the snippet will immediately terminate.

The next section of code executes the database query that will populate new journal entries. The snippet uses an IF/ELSE block to determine whether the time of the last query is available. To meet requirement three, if the time of the last query is available, it is used in the WHERE clause of the new query. If the time of the last query is unavailable, a timestamp for 60 seconds ago is used in the WHERE clause:

if meta is not None and meta.has_key('time'):

logger.debug("Have valid meta data, using last query time in WHERE clause")

try:

cur.execute("""(SELECT session_id, state, user, UNIX_TIMESTAMP(login_time) as login, UNIX_TIMESTAMP(logout_time) as logout_time FROM master_access.access_log WHERE login_time > FROM_UNIXTIME(%s)) UNION (SELECT UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW())) ORDER BY login DESC""", (meta['time'],))

except MySQLdb.Error, e:

create_error = True

create_problem = "%s: %s" % (e.args[0], e.args[1])

else:

logger.debug("No valid meta data, using 60 seconds ago in WHERE clause")

try:

cur.execute("""(SELECT session_id, state, user, UNIX_TIMESTAMP(login_time) as login, UNIX_TIMESTAMP(logout_time) as logout_time FROM master_access.access_log WHERE UNIX_TIMESTAMP(login_time) > (UNIX_TIMESTAMP() - 60)) UNION (SELECT UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW())) ORDER BY login DESC""")

except MySQLdb.Error, e:

create_error = True

create_problem = "%s: %s" % (e.args[0], e.args[1])

 

The query selects the fields listed in requirement two. The query uses a UNION statement in conjunction with an ORDER BY to make the first row in the result set always return all NOW() timestamps. Again, the snippet uses TRY/EXCEPT blocks to catch any errors. All time values are converted to UNIX timestamps; storing UNIX timestamps for the login time and logout time allow the presentation options to convert to human-readable timestamps based on the user's preferences. To meet requirement six, collection of journal entry updates must still be performed if this query fails; therefore, instead of using COLLECTION_PROBLEM and PROBLEM_STR, the snippet uses the variables create_error and create_problem to track errors from this query.

If the query is successful, the first row, which contains the NOW() timestamp, is stored as meta data:

if create_error == False:

now = cur.fetchone()

last_query = now[3]

if last_query:

meta_data = {'time':last_query}

logger.debug("Setting Meta Data: %s" % meta_data)

try:

set_app_instance_meta_data(meta_data)

except SerializationError as e:

INTERNAL_ALERTS.append((519, "Could not serialize meta data for storage for did:%s, app id:%s, error: %s" % (app_id, did, e)))

logger.debug("SerializationError when setting meta data: %s" % e)

 

Similar to the retrieval of this meta data, the set_app_instance_meta_data call is in a TRY/EXCEPT block, and the snippet generates an internal alert if a serialization error occurs.

The snippet now fetches all remaining rows from the result of the query. Each row is used to create a new journal entry. This section of code is inside the "if create_error == False" block:

results = cur.fetchall()

 

for row in results:

if row[1] == 0:

entry = create_entry(row[0], JOURNAL_STATE_CLOSED)

entry_collections = {'Username':row[2], 'Login':row[3], 'Logout':row[4]}

elif row[1] == 3:

entry = create_entry(row[0], JOURNAL_STATE_ABANDONED)

entry_collections = {'Username':row[2], 'Login':row[3], 'Logout':row[4]}

else:

entry = create_entry(row[0], JOURNAL_STATE_OPEN)

entry_collections = {'Username':row[2], 'Login':row[3]}

#logger.debug(entry_collections)

entry.update_collected_data(entry_collections)

EM7_RESULT.append(entry)

 

For each row, the snippet calls the create_entry method. The snippet uses the session_id field from the database as the journal key and determines the state of the new journal entry by using the mapping in requirement two. The snippet creates a dictionary called entry_collections that contains all available collection objects. For journal entries in an open state, the logout time is not included. The entry_collections dictionary uses the variable names used for each collection object as keys. To associate the collected data with the journal entry, the snippet calls update_collected_data using the entry_collections dictionary as the parameter. To pass the journal entry to SL1 for storage, the snippet appends the new journal entry to EM7_RESULT.

To get a list of journal entries that must be checked for updates, the snippet calls the bulk_get_open_entries function. The snippet iterates through the list of returned journal entries, querying for each user session:

open_entries = bulk_get_open_entries()

for entry in open_entries:

try:

cur.execute("""SELECT session_id, state, logout_time FROM master_access.access_log WHERE session_id = %s""", (entry.entry_key,))

except MySQLdb.Error, e:

update_error = True

update_problem = "%s: %s" % (e.args[0], e.args[1])

 

The snippet uses the key for each journal entry the WHERE clause of the query. Similar to how errors in the query for new entries are recorded, the update_error and update_problem are used to record errors in this query.

If the query is successful, the snippet checks the state of the user session to see if the corresponding journal entry must change state:

if update_error == False:

result=cur.fetchone()

if result is None:

entry.set_state(JOURNAL_STATE_ERROR)

EM7_RESULT.append(entry)

elif result[1] == 0:

entry.close()

entry_collections = {'Logout':result[2]}

entry.update_collected_data(entry_collections)

EM7_RESULT.append(entry)

elif result[1] == 3:

entry.abandon()

entry_collections = {'Logout':result[2]}

entry.update_collected_data(entry_collections)

EM7_RESULT.append(entry)

 

To meet requirement five, if the query returns no rows (i.e. the user session no longer in the table), the snippet sets the journal entry to the error state. To meet requirement four, if the user session is in state 0 or 3 (logged out or expired), the snippet sets the journal entry to the closed or abandoned state, respectively. If the journal entry is set to a closed or abandoned state, the snippet adds the value for the logout time collection object to the journal entry. If the journal entry has been updated, the snippet appends the updated object to the EM7_RESULT list to pass the updated information back to SL1.

The snippet has finished collecting new and existing journal entries. To meet requirement six, the snippet must check the create_error and update_error variables for the different error combinations:

if update_error == True and create_error == True:

COLLECTION_PROBLEM = True

PROBLEM_STR = "No database queries successful: %s: %s" % (create_problem, update_problem)

elif update_error == True:

INTERNAL_ALERTS.append((519, "Query failure when updating journal entries, but new entry creation successful. did:%s, app id:%s, error: %s" % (app_id, did, update_problem)))

elif create_error == True:

INTERNAL_ALERTS.append((519, "Query failure when creating journal entries, but entry update successful. did:%s, app id:%s, error: %s" % (app_id, did, create_problem)))

 

If both the query to collect new journal entries and a query to collect an existing journal entry failed, the snippet sets COLLECTION_PROBLEM to "True" to report a missed poll, and populates PROBLEM_STR with an appropriate error message. If either the query to collect new journal entries or the queries to collect an existing journal entry were successful, the snippet does not report a missed poll, but does generate an internal alert. The internal alert uses alert ID 519, which will trigger a minor event.

To add this snippet code to the example Dynamic Application you created, perform the following steps:

  • Click the Snippets tab in the Dynamic Application Editor pane.
  • Click the wrench icon () for the "Collect Login Data" snippet.
  • Insert the snippet code in the Snippet Code field. A full listing of the snippet code is included in the last section.
  • Click the Save button.

Creating the Presentation Objects

To display the collection objects in the Journal View page for this Dynamic Application, the Dynamic Application must include one or more presentation objects. Presentation objects define how collected data will be displayed for each journal entry in the Journal View page. This example will use three presentation objects, one for each collection object. To create the presentation objects for this Dynamic Application:

  1. Click the Presentations tab in the Dynamic Application Editor pane.
  2. Supply values in the following fields to create a presentation object for the username collection object:
    • Report Name. The name of the presentation object. This name will be displayed as a column heading in the table of journal entries in the Journal View page. Enter "Username" in this field.
    • Summarization State. Specifies whether SL1 should display this presentation object in the Journal View page. Select Enabled in this field.
    • Column Order. Specifies the order in which the columns for each presentation object will be displayed in the Journal View page. Columns are displayed in ascending Column Order, from left to right. For this example, the Username presentation will be the first column on the left. Enter "1" in this field.
    • Column Width Type. Specifies whether SL1 should display the column with a width relative to the other columns or using a fixed width in pixels. This example uses relative column widths. Select Relative width (x) in this field.
    • Column Width. Specifies the width of the column in the Journal View page, either relative to the other columns or by number of pixels. This example uses relative column widths, with the username column displayed at half the width of the other two presentation object columns. Enter "1" in this field.
    • Column data type. Specifies the data type of the values displayed in this column. Usernames are text strings. Select String template in this field.
    • Indexing and sorting. Specifies whether the table of journal entries can be sorted by the values in this column. This example allows sorting on all columns. Select Enabled (column can be sorted according to data type) in this field.
    • Display formula. Specifies the collection objects to display in this column. Select Username in the select list below the Display formula field, then click the Add button.
  3. Click the Save button, then click the Reset button to clear the values you entered.
  4. Repeat steps two and three to create a presentation object for the login time collection object. Use the following values:
    • Report Name. Enter "Login Time" in this field.
    • Active State. Select Enabled in this field.
    • Column Order. For this example, the Login Time presentation will be the second column. Enter "2" in this field.
    • Column Width Type. This example uses relative column widths. Select Relative width (x) in this field.
    • Column Width. This example uses relative column widths, with the username column displayed at half the width of the other two presentation object columns. Enter "2" in this field.
    • Column data type. Specifies the data type of the values displayed in this column. Login time is stored as a UNIX timestamp. Select Date and time in this field. SL1 will convert the collected values to human-readable timestamps based on each user's preferences.
    • Indexing and sorting. This example allows sorting on all columns. Select Enabled (column can be sorted according to data type) in this field.
    • Display formula. Specifies the collection objects to display in this column. Select Login Time in the select list below the Display formula field, then click the Add button.
  1. Repeat steps two and three to create a presentation object for the logout time collection object. Use the following values:
    • Report Name. Enter "Logout" in this field.
    • Active State. Select Enabled in this field.
    • Column Order. For this example, the Logout Time presentation will be the third column. Enter "3" in this field.
    • Column Width Type. This example uses relative column widths. Select Relative width (x) in this field.
    • Column Width. This example uses relative column widths, with the username column displayed at half the width of the other two presentation object columns. Enter "2" in this field.
    • Column data type. Specifies the data type of the values displayed in this column. Logout time is stored as a UNIX timestamp. Select Date and time in this field. SL1 will convert the collected values to human-readable timestamps based on each user's preferences.
    • Indexing and sorting. This example allows sorting on all columns. Select Enabled (column can be sorted according to data type) in this field.
    • Display formula. Specifies the collection objects to display in this column. Select Logout Time in the select list below the Display formula field, then click the Add button.

Creating a Credential and Using the Dynamic Application

To use the example Dynamic Application, you must first create a database credential to align with the Dynamic Application. Perform the following steps to create a database credential for a ScienceLogic Database:

  • Go to the Credential Management page (System > Manage > Credentials).
  • Click the Actions menu, then select Create Database Credential. The Credential Editor page appears.
  • Supply values in the following fields:
    • Profile Name. Enter a name for the credential.
    • DB Type. Specifies which type of database the credential can be used for. Select MySQL in this field.
    • DB Name. Specifies the default database for the credential. The example snippet does not use this field, but a value must be specified. Enter "master" in this field.
    • DB User. Specifies the username to use when connecting to the database. Enter "root" in this field.
    • Password. Specifies the password to use when connecting to the database. Enter the password for the "root" user on your ScienceLogic Database in this field.
    • Hostname/IP. Specifies the hostname or IP address to connect to. If you are aligning this Dynamic Application to a ScienceLogic Database modeled as a device in your system, enter "%D" in this field to use the IP address of the aligned device. If you are not aligning this Dynamic Application to a ScienceLogic Database modeled as a device in your system, enter the hostname or IP address of your ScienceLogic Database in this field.
    • Port. Specifies the port to connect to. Enter "7706" in this field.
  • Click the Save button.

To align this Dynamic Application to a device, perform the following steps:

If you entered "%D" in the Hostname/IP field for your credential, you must align the Dynamic Application to a ScienceLogic Database.

  • Go to the Device Manager page (Devices > Device Manager).
  • Click the wrench icon () for the device you want to align with the Dynamic Application. The Device Properties page appears.
  • Click the Collections tab. The Dynamic Application Collections page appears.
  • Click the Action menu and select Add Dynamic Application.
  • In the Dynamic Application Alignment modal page, select our example Dynamic Application, Snippet Journal Example. Select the credential you created for your ScienceLogic Database.
  • Click the Save button. The page refreshes, and the Snippet Journal Example Dynamic Application appears in the list of Dynamic Applications.

For the Dynamic Application to collect at least one journal entry, a user must log in to the system after the Dynamic Application has been aligned to the device. Log out, then log in to the SL1 system. To view collected data for this Dynamic Application:

  • Go to the Device Manager page (Devices > Device Manager).
  • Click the graph icon () for the device you aligned with the Dynamic Application. The Device Summary page appears.
  • Click the Journals tab. The Journal View page appears.
  • If multiple Journal Dynamic Applications are aligned with this device, click Snippet Journal Example in the left Navbar.
  • By default, only closed journal entries are displayed. Remove "closed" from the State search filter.

All collected journal entries appear on the Journal View page:

Full Snippet Code Listing

import MySQLdb

COLLECTION_PROBLEM = False

create_error = False

update_error = False

try:

meta = get_app_instance_meta_data()

except DeserializationError as e:

INTERNAL_ALERTS.append((519, "Could not deserialize stored meta data for did:%s, app id:%s, error: %s" % (app_id, did, e)))

logger.debug("Credential: %s" % (cred_details,))

logger.debug("Collection objects: %s" % (collection_objects,))

if cred_details['cred_type'] != 2:

COLLECTION_PROBLEM = True

PROBLEM_STR = "Database credential not aligned"

else:

try:

conn = MySQLdb.connect(user=cred_details['cred_user'], passwd=cred_details['cred_pwd'], host=cred_details['cred_host'], port=cred_details['cred_port'])

cur = conn.cursor()

except MySQLdb.Error, e:

COLLECTION_PROBLEM = True

PROBLEM_STR = "Database connection error: %s: %s" % (e.args[0], e.args[1])

if COLLECTION_PROBLEM == False:

if meta is not None and meta.has_key('time'):

logger.debug("Have valid meta data, using last query time in WHERE clause")

try:

cur.execute("""(SELECT session_id, state, user, UNIX_TIMESTAMP(login_time) as login, UNIX_TIMESTAMP(logout_time) as logout_time FROM master_access.access_log WHERE login_time > FROM_UNIXTIME(%s)) UNION (SELECT UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW())) ORDER BY login DESC""", (meta['time'],))

except MySQLdb.Error, e:

create_error = True

create_problem = "%s: %s" % (e.args[0], e.args[1])

else:

logger.debug("No valid meta data, using 60 seconds ago in WHERE clause")

try:

cur.execute("""(SELECT session_id, state, user, UNIX_TIMESTAMP(login_time) as login, UNIX_TIMESTAMP(logout_time) as logout_time FROM master_access.access_log WHERE UNIX_TIMESTAMP(login_time) > (UNIX_TIMESTAMP() - 60)) UNION (SELECT UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW()),UNIX_TIMESTAMP(NOW())) ORDER BY login DESC""")

except MySQLdb.Error, e:

create_error = True

create_problem = "%s: %s" % (e.args[0], e.args[1])

if create_error == False:

now = cur.fetchone()

last_query = now[3]

if last_query:

meta_data = {'time':last_query}

logger.debug("Setting Meta Data: %s" % meta_data)

try:

set_app_instance_meta_data(meta_data)

except SerializationError as e:

INTERNAL_ALERTS.append((519, "Could not serialize meta data for storage for did:%s, app id:%s, error: %s" % (app_id, did, e)))

logger.debug("SerializationError when setting meta data: %s" % e)

results = cur.fetchall()

for row in results:

if row[1] == 0:

entry = create_entry(row[0], JOURNAL_STATE_CLOSED)

entry_collections = {'Username':row[2], 'Login':row[3], 'Logout':row[4]}

elif row[1] == 3:

entry = create_entry(row[0], JOURNAL_STATE_ABANDONED)

entry_collections = {'Username':row[2], 'Login':row[3], 'Logout':row[4]}

else:

entry = create_entry(row[0], JOURNAL_STATE_OPEN)

entry_collections = {'Username':row[2], 'Login':row[3]}

#logger.debug(entry_collections)

entry.update_collected_data(entry_collections)

EM7_RESULT.append(entry)

open_entries = bulk_get_open_entries()

for entry in open_entries:

try:

cur.execute("""SELECT session_id, state, logout_time FROM master_access.access_log WHERE session_id = %s""", (entry.entry_key,))

except MySQLdb.Error, e:

update_error = True

update_problem = "%s: %s" % (e.args[0], e.args[1])

if update_error == False:

result=cur.fetchone()

if result is None:

entry.set_state(JOURNAL_STATE_ERROR)

EM7_RESULT.append(entry)

elif result[1] == 0:

entry.close()

entry_collections = {'Logout':result[2]}

entry.update_collected_data(entry_collections)

EM7_RESULT.append(entry)

elif result[1] == 3:

entry.abandon()

entry_collections = {'Logout':result[2]}

entry.update_collected_data(entry_collections)

EM7_RESULT.append(entry)

if update_error == True and create_error == True:

COLLECTION_PROBLEM = True

PROBLEM_STR = "No database queries successful: %s: %s" % (create_problem, update_problem)

elif update_error == True:

INTERNAL_ALERTS.append((519, "Query failure when updating journal entries, but new entry creation successful. did:%s, app id:%s, error: %s" % (app_id, did, update_problem)))

elif create_error == True:

INTERNAL_ALERTS.append((519, "Query failure when creating journal entries, but entry update successful. did:%s, app id:%s, error: %s" % (app_id, did, create_problem)))