Forum Discussion

konerus's avatar
konerus
Adept
4 years ago

Is logging possible in Khoros?

Is there a way to log information of User Id and the kind of a variable when it hits certain code?

  • I suppose it depends on what kind of logging you're hoping to accomplish.

    For example, one option is to use the FreeMarker logging utilities if you're wanting some server-side logging to occur.

    Alternatively, if you are wanting to have some client-side logging for troubleshooting/debugging purposes in the browser console (i.e. Developer Tools > Console), then you can leverage jQuery to do this.

    In our environment, I created a macro called custom.macro.logging.ftl to simplify client-side logging in our customizations, which looks like this:

    <#------------------------------------------------
      Functions and Macros for Logging and Debugging
      Created By:           Jeff Shurtliff
      Last Modified By:     Jeff Shurtliff
      Last Modified Date:   2020-11-03
    ------------------------------------------------->
    
    <#-------------------- Macro: consoleLog -------------------->
    <#-- This macro prints an entry to the browser JavaScript console (i.e. console.log) -->
    <#macro consoleLog logEntry="">
      <@liaAddScript>
        ; (function ($) {
          console.log("${logEntry}");
        })(LITHIUM.jQuery);
      </@liaAddScript>
    </#macro>
    
    
    <#-------------------- Macro: consoleError -------------------->
    <#-- This macro prints an error to the browser JavaScript console (i.e. console.error) -->
    <#macro consoleError logEntry="">
      <@liaAddScript>
        ; (function ($) {
          console.error("${logEntry}");
        })(LITHIUM.jQuery);
      </@liaAddScript>
    </#macro>
      
    
    <#-------------------- Macro: consoleDebug -------------------->
    <#-- This macro prints a debug message to the browser JavaScript console (i.e. console.debug) -->
    <#macro consoleDebug logEntry="">
      <@liaAddScript>
        ; (function ($) {
          console.debug("${logEntry}");
        })(LITHIUM.jQuery);
      </@liaAddScript>
    </#macro>
    
    
    <#-------------------- Macro: consoleInfo -------------------->
    <#-- This macro prints an info message to the browser JavaScript console (i.e. console.info) -->
    <#macro consoleInfo logEntry="">
      <@liaAddScript>
        ; (function ($) {
          console.info("${logEntry}");
        })(LITHIUM.jQuery);
      </@liaAddScript>
    </#macro>
    
    
    <#-------------------- Macro: consoleWarn -------------------->
    <#-- This macro prints a warning message to the browser JavaScript console (i.e. console.warn) -->
    <#macro consoleWarn logEntry="">
      <@liaAddScript>
        ; (function ($) {
          console.warn("${logEntry}");
        })(LITHIUM.jQuery);
      </@liaAddScript>
    </#macro>

    Then in my other custom components/macros/functions I am able to easily generate log entries by importing the macro file and calling one of the macros above, as demonstrated below.

    <#-- Import the macro file -->
    <#import 'custom.macro.logging' as logging />
    
    <#-- Attempt to get the user ID -->
    <#attempt>
      <#assign userId = user.id />
      <@logging.consoleDebug "The User ID is ${userId}" />
    <#recover>
      <@logging.consoleError "Encountered an exception while retrieving the User ID" />
    </#attempt>

    Then while testing in the browser you can monitor the Console tab in Developer Tools and have a better understanding of what might be failing and why.

    (I like to include the text "Encountered an exception while..." in error messages within the <#recover> directive because it reminds me that I should check out the Toolbox to see what the verbose FreeMarker error was so I can troubleshoot even further.)

    I hope this helps!

    • konerus's avatar
      konerus
      Adept

      Thank you for the quick response Jeff. I am looking at server side logging. When we use the utils where are the logs stored and how can I get a copy of it?

      • Claudius's avatar
        Claudius
        Boss

        konerus Maybe you can share a bit more about what user behaviour you are trying to create a log of. Because Khoros already has a lot of Analytics capturing built-in which you might consider "logging" in a certain way.

    • jeffshurtliff's avatar
      jeffshurtliff
      Boss

      I realized I forgot to comment on the other part of your question about getting "the kind of a variable" which I assume you mean the data type of a variable, e.g. string, hash, sequence, etc.

      FreeMarker has some quite a few built-ins to check the data type of a variable, which are explained in the official documentation.

      However, to avoid having to call a whole bunch of built-ins whenever I want to know the data type of one of my variables, I created the function below which really comes in handy.

      <#-------------------- Function: checkDataType -------------------->
      <#-- This function returns the data type of the object -->
      <#function checkDataType object simple=false>
        <#local dataType = "unknown" />
        <#attempt>
          <#if object?is_string>
            <#local dataType = "string" />
          <#elseif object?is_number>
            <#local dataType = "number" />
          <#elseif object?is_boolean>
            <#local dataType = "boolean" />
          <#elseif object?is_sequence>
            <#local dataType = "sequence" />
            <#if simple?? && !simple>
              <#attempt>
                <#local subType = checkDataType(object[0]) />
                <#if subType?? && subType != "unknown">
                  <#local dataType = dataType + "+${subType}" />
                </#if>
              <#recover>
                <@logging.consoleError "Encountered an exception when attempting to determine data subtype for object" />
              </#attempt>
            </#if>
          <#elseif object?is_hash>
            <#if simple?? && !simple && object?is_hash_ex>
              <#local dataType = "extended_hash" />
            <#else>
              <#local dataType = "hash" />
            </#if>
          <#elseif object?is_date_like>
            <#local dataType = "date_like" />
          <#elseif object?is_method>
            <#local dataType = "method" />
          <#elseif object?is_macro>
            <#local dataType = "macro_function" />
            <#--  Correct syntax for checking marcos is checkDataType(macro) instead of checkDataType(<@macro></@macro>) -->
            <#--  Correct syntax for checking functions is checkDataType(myFunc) instead of checkDataType(myFunc()) -->
          </#if>
        <#recover>
          <@logging.consoleError "Encountered an exception when attempting to determine data type for object" />
        </#attempt>
        <#return dataType />
      </#function>

      This way I can use the function to quickly identify the data type and take action accordingly, such as in the example below.  (I keep the function in a macro file called custom.macro.common.utils.ftl which is why you see it referenced as such below.)

      <#-- Import common utilities -->
      <#import 'custom.macro.common.utils' as commonUtils />
      
      <#assign someVar = 12345 />
      
      <#-- Ensure the variable below is a string -->
      <#assign dataType = commonUtils.checkDataType(someVar) />
      <#if dataType == 'number' || dataType == 'boolean'>
        <#assign someVar = someVar?c />
      </#if>
      
      This is my variable: ${someVar}

      Hope this helps!