Help needed for scripting for runtime fields

Hello everyone,

I am completely new to Elastic and scripting in general. I was told to install ElasticStack on our network for monitoring purposes.
I now have both Elasticsearch and Kibana installed. I am currently trying to create dashboards/visualizations for monitoring. It's great that it comes with a lot of pre-loaded fields and dashboards, but I am trying to create new fields/data views to create new dashboards.

I am trying to create a data view for all login attempts. Similar to the pre-loaded ssh login attempts (i.e. system.auth.ssh.events).
I tried following the 'Elastic Runtime Field example repository' I found online and few others, but it's not giving me the correct results, so I know I'm doing something wrong.

So far, I created the data view with the name 'system.auth.login.event', I enabled 'Set Value' and put the following in the 'Define Script' field:

if(!doc.containsKey('the password for the login keyring was invalid.')) {
  emit('Login Failed');
}

When I go into Discover and select my new created field in the 'Available fields' column, I get millions of results, which I know is incorrect because if I search for just the string "the password for the login keyring was invalid" in the KQL filter, I get under 100 results.

Could someone please tell me the correct scripting or a document for me to better understand it? Thank you.

Hi @jreyes25

welcome to the Kibana community.

When I go into Discover and select my new created field in the 'Available fields' column, I get millions of results, which I know is incorrect because if I search for just the string "the password for the login keyring was invalid" in the KQL filter, I get under 100 results.

How do you search for the in KQL?

I guess the problem there is to select the right field in the condition:

if(!doc["<field here">].value === 'the password for the login keyring was invalid.') {
  emit('Login Failed');
}
1 Like

Thank you for the welcome and the response.

In this case, I specifically searched for the message that comes up in my logs on the machine (/var/log/secure), which is "the password for the login keyring was invalid."
When I search for that message in the KQL search bar, it comes with the following text (there's a lot more information that comes up, but I want to focus on the following):

"message": [
        "gkr-pam: the password for the login keyring was invalid."
],

When I use the condition you mentioned, I get the following script error: class_cast_exception: Cannot cast from [boolean] to [java.lang.Object].
This is exactly was I entered:

if(!doc["message"].value === 'the password for the login keyring was invalid.') {
  emit('Login Failed');
}

I'm assuming I replace "field here" with the field I found in the logs, which is "message". Is that correct?

What's the mapping for the message field? Is it a nested field?

It is not a nested field. The other information is just information about the host (i.e. "host.name", "host.os.name", "host.ip", etc.)

But I believe this is what I'm looking for:

This guy was trying to do the same as myself, but I'm just trying to pull a different message from the logs. I just don't know how to write the code.

So far I went into logs-* and added a new field (system.auth.login.events). Now I just need to set the correct value for the script.

Again, thank you for taking your time to help me.

^^^^ @jreyes25 Without this answer we can not help.

Do you know how to get the mapping for this field?

Thank you for the reply.

I believe I found it in the index .ds-logs-auditd.log-defualt:

"message": {
  "type": "match_only_text"

I read that you cannot aggregate on "match_only_text". I would have to create a sub field "keyword" for it to work.

I created the subfield using the following:

PUT my_index_name/_mapping
{
  "properties": {
    "message" : {
      "type" : "match_only_text",
      "fields": {
        "keyword": {
          "type" : "keyword"
        }
      }
    }
  }
}

Now I have the mapping as keyword (message.keyword) instead of match_text_only.

I tried the above code and replaced "message" with "message.keyword", but it errors out with the following message: No field found for [message.keyword] in mapping.

I'm still unsure of what to put exactly in the script field. Hopefully I'm on the right track.

Just because you updated the mapping does not mean all your documents are updated... you will need to reingest or reindex your data...

There could be something else but that is the first thing that comes to mind

Ok. So I created a new index and copy/pasted the mappings from the old one to the new one. Then I reindexed the old to the new with:

POST _reindex
{
  "source": {
     "index": "<old_index>"
   },
  "dest": {
      "index": "<new_index>"
   }
}

Everything completed successfully.

What would the next step be? Because I tried using the same code, but I still get a "No field found for [message.keyword] in mapping." error.

Did you create the index with the new mapping before you reindexed? Otherwise you just end up with the same issue.

Show the mapping of the new index?

Show Samples of the Data / Documents?

Can you access both the text and keyword fields in Discover?

I need to see something to help :slight_smile:

I'm sorry about that.

The network my ElasticStack is on is air-gapped, so I'm unable to get any screenshots.

But to answer your questions.

  • Yes, I did add the new mappings before I reindexed it and I see the mappings when run a GET request.
  • In Discover, I do have access to the text field (message) and I see the keyword field for the new mapping (message.keyword) in the KQL search bar, but I do not see the message.keyword in the 'available fields' on the left column of Discover. I do however see message.keyword in the Dataviews under Stack Management.


Assuming you are on a relatively new version of Elastic Stack You will only see the single field name in the discover list of fields even though it is a multi-field.

The fact you can find it in the KQL bar is validation and you should be able to filter with the message.keyword on exact matches... Can you do that?

If so So that all seems correct!

So now ... what were we trying to accomplish? now that we have a keyword!

Ahh the Script! Here is a sample in the Data View... If you want to us it in queries you need to add it to the mapping as a runtime field ... you do NOT have to reindex for that

if(doc['message.keyword'].value == 'ACMEMORE-test4'){
  emit('Login Failed');
}
else emit('Login Succes');

Ok. Thank you and that is correct. I can see it in the KQL bar as shown in your picture. Also, I am on version 8.4.3.

So when I start typing the script, "message.keyword" pops up showing it's availabe.

But when I finish the script, I get the same error "No field found for [message.keyword] in mapping". Did I miss a step?

Below are the pictures of what I'm talking about.


So hard to debug with screen shots...

  1. Delete and recreate the Data View?

  2. does the data view reference both indices that have the new mapping and some that do not have the new mapping... That seems likely that can be the issue....

The actual test document on the Right side of the last image can you find message.keyword in that document. I suspect not because the Index Pattern is Grabbing a document from some other document that does not have the message.keyword field

So I think you have mixed documents you can put some error handling let me figure out that... you have the worse kind of mixed some with message as text and some with message with text and keyword

I think something like this will work..

if(doc["message.keyword"].empty) {
  emit('No Login Message');
  return;
}
if(doc['message.keyword'].value == 'Login Totally Failed My Friend, access denied'){
  emit('Login Failed');
}
else emit('Login Succes');

Hello, sorry for the late response. I tried the code, but I still get the same error saying that the 'message.keyword' field was not found.

So I rolled back my ES VM from the last snapshot to when I didn't change any settings or mappings.
I read that if I'm just adding to a mapping, I do not need to reindex, which in this case I am just adding to it.

The index I'm adding to is a built-in index (which is hidden) called '.ds-logs-system-auth-default-YYYY.MM.DD-000001'

The section of the index I'm adding the mapping to looks like this:

{
  ".ds-logs-system-auth-default-YYYY.MM.DD-000001" {
     "mappings": {
         "properties": {
             "message" : {
                  "type" : "match_only_text"
                 }
              }
          }
      },

I'm using PUT to add to this index to edit the 'message' mapping to add 'keyword' to it:

PUT .ds-logs-system-auth-default-YYYY.MM.DD-000001/_mapping
{
  "properties": {
    "message" : {
      "type" : "match_only_text",
      "fields": {
        "keyword": {
          "type" : "keyword"
        }
      }
    }
  }
}

After completing successfully, I see the field 'message.keyword' in my Data View and my KQL bar in Discover.

When I add a new field, i.e. 'login.events' and set value mentioned above (I tried everyone that was recommended), I still get the error that it cannot find the 'message.keyword' mapping.

I'm not exactly sure where I'm going wrong.

Hi @jreyes25 I think there is a fundamental misunderstanding just adding a mapping to an existing index does not make the field available... it is like adding a column in a database now you have a new column but there is no data in it.

Just adding a field to the mapping does not put the data into that field... It just updates the schema.

You need to add that mapping to the template so that when a new index is when the data comes in it gets put into this field...

Do you have an event.original field? that is probably already a keyword

oh ok. I understand. How would I add the mapping to the template?
Yes I do have a event.original field that is already 'keyword'.