message logging using KVM approach

snehansu
Participant III

Hi,

Need a suggestion with better approach instead of using KVM and also create new line in the splunk for all the requests .

For logging mechanism , I used message logging policy and I created a variable in the message tag, that variable pulling the data from the KVM.

The reason I used KVM,

1- Development team can add/update the variables in the log

2- Create a new line in the splunk for all the requests

Logging policy:

<Message>{logTemplate}</Message>

requestLogTemplate in KVM: {"apiproxyName":"{apiproxy.name}";"clientReceivedStartTime":"{client.received.start.time}";"clientEndTime":"{system.time}";"queryParam":"{request.querystring}"}

Created a JS policy to retrieve requestLogTemplate from KVM and create new line.

logTemplate = logTemplate+ '\n';

1 1 422
1 REPLY 1

Your question seems to be abbreviated.

But I think the general idea is that you would like the MessageLogging policy to evaluate a message template TWICE.

It doesn't do that.

Here's what I mean. Suppose you use the string {logTemplate} within an element that accepts a Message Template, like the Message element in the MessageLogging policy:

<Message>{logTemplate}</Message>

The curly braces here tells the policy "for the value here, replace every occurrence of balanced curly braces surrounding a variable name, with the value contained in the named variable". If the context variable "logTemplate" contains the word "dog" then the Message will evaluate to "dog". Conversely, if you used this as a template:

<Message>{logTemplate}:{system.uuid}</Message>

Then, the result would evaluate to something like "dog:1b857cb4-b32e-458d-b94e-626e3d634755". (where the thing after the colon would be a uuid corresponding to the server handling the request).

What you want to do, apparently, is evaluate the template TWICE. You want it to do this:

"for the value here, start by replacing every occurrence of balanced curly braces surrounding a variable name, with the value contained in the named variable. THEN, do it again."

But that's not how message templates work. That's not how any of this works!

But I understand why you'd want to do it. I get it. It would be so nice, so simple. If only. . . .


The workaround I can suggest is to evaluate the message template "manually" within a JavaScript callout. Set the variable "logMessage" to the resulting value.

Then, use

<Message>{logMessage}</Message>

And the logMessage will contain the expanded message.

You might be wondering exactly how you can evaluate the message template within JavaScript. Here's what I use:

(function () {
  'use strict';
  var variableNameRe = "[^ \t\n\"',/\\\\{}]+?"; // non-greedy capture
  var varPrefixRe = '{';
  var varSuffixRe = '}';
  var variableRegex = new RegExp( varPrefixRe + '(' + variableNameRe + ')' + varSuffixRe);


  function MessageTemplate(tmpl) {
    this.template = tmpl;
  }


  MessageTemplate.prototype.fill = function() {
    // substitute all names surrounded by {curly_braces} in the template
    // with the value of the corresponding context variables
    var match;
    var template = this.template;
    match = variableRegex.exec(template);
    while (match !== null) {
      var variableName = match[1];
      var value = context.getVariable(variableName);
      if (value && value !== '') {
        template = template.replace('{' + variableName + '}', value);
      }
      else {
        template = template.replace('{' + variableName + '}', 'n/a');
      }
      match = variableRegex.exec(template);
    }
    return template + ''; // coerce to JS String
  };


  // export
  var globalScope = (function(){ return this; }).call(null);
  globalScope.MessageTemplate = MessageTemplate;


}());

Put that in a file called messageTemplate.js . Then, your JS code to fill the message template might be named fillPayload.js, and would look like this:

var inputString = context.getVariable(properties.source);
var template = new MessageTemplate(inputString);
var payload = template.fill(); // evaluate it against context
context.setVariable(properties.output, payload);

The JS policy config should be like this:

<Javascript name='JS-FillTemplate'>
  <Properties>
    <Property name='source'>logTemplate</Property>
    <Property name='output'>logMessage</Property>
  </Properties>
  <IncludeURL>jsc://messageTemplate.js</IncludeURL>
  <ResourceURL>jsc://fillPayload.js</ResourceURL>
</Javascript>