# JSON Parsing Issue

**URL:** <https://discuss.elastic.co/t/json-parsing-issue/265219>\
**Category:** Logstash\
**Created:** [February 23, 2021, 3:41pm UTC](https://discuss.elastic.co/t/json-parsing-issue/265219 "2021-02-23T15:41:06Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![wwalker](https://avatars.discourse-cdn.com/v4/letter/w/43a26b/32.png) [@wwalker](https://discuss.elastic.co/u/wwalker)\
**Post date:** [February 23, 2021, 3:41pm UTC](https://discuss.elastic.co/t/json-parsing-issue/265219/1 "2021-02-23T15:41:06Z")

</div>

Running Logstash 7.10 and having an issue with parsing a JSON-ish field. Here's my filter config:

```auto
    if [vpn][tunnel_type] {
      mutate {
        gsub => [
          "[vpn][tunnel_type]", '\=\>', ':'
        ]
      }
      json {
        source => "[vpn][tunnel_type]"
      }
  }

```

The error message I get in the pipeline logs is:

```auto
Error parsing json {:source=>"[vpn][tunnel_type]", :raw=>{"tunnel_id"=>"1087764505", "tunnel_type"=>"ssl-tunnel", "tunnel_ip"=>"192.168.1.1"}, :exception=>java.lang.ClassCastException}

```

Am I reading it right that the raw JSON coming in is formatted with `=>` instead of `:`? I've tried both the gsub regex as shown above as well as just `=>`. Is there a different syntax I should be using with gsub? Or maybe I'm reading the log entry wrong and the raw message is also missing the opening and close script blocks `{}`?

---

<div class="post-metadata">

**Author:** ![Badger](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/badger/32/25190_2.png) [@Badger](https://discuss.elastic.co/u/Badger)\
**Post date:** [February 23, 2021, 4:07pm UTC](https://discuss.elastic.co/t/json-parsing-issue/265219/2 "2021-02-23T16:07:03Z")

</div>

Your [vpn][tunnel\_type] is not a string, it is an object. So your mutate filter does not do anything. Trying to parse this object with a json filter

```
    "tunnel_type" => {
          "tunnel_id" => "1087764505",
        "tunnel_type" => "ssl-tunnel",
          "tunnel_ip" => "192.168.1.1"
    }

```

gets the error message

```auto
 Error parsing json {:source=>"[vpn][tunnel_type]", :raw=>{"tunnel_id"=>"1087764505", "tunnel_ip"=>"192.168.1.1", "tunnel_type"=>"ssl-tunnel"}, :exception=>java.lang.ClassCastException: ...

```

If it were a string then you would get the error

```auto
Error parsing json {:source=>"[vpn][tunnel_type]", :raw=>"{\"tunnel_id\"=>\"1087764505\", \"tunnel_type\"=>\"ssl-tunnel\", \"tunnel_ip\"=>\"192.168.1.1\"}", :exception=>#<LogStash::Json::ParserError: Unexpected character ('=' (code 61)): ...

```

If you need to move the contents of [vpn][tunnel\_type] to the top level use [ruby](https://discuss.elastic.co/t/how-to-dynamically-move-nested-key-value-to-root-level/180006/2).

---

<div class="post-metadata">

**Author:** ![wwalker](https://avatars.discourse-cdn.com/v4/letter/w/43a26b/32.png) [@wwalker](https://discuss.elastic.co/u/wwalker)\
**Post date:** [February 23, 2021, 4:20pm UTC](https://discuss.elastic.co/t/json-parsing-issue/265219/3 "2021-02-23T16:20:59Z")

</div>

Pulling code from where I used ruby last...because I don't know ruby that well, would this be the proper usage?

```auto
ruby {
  code => "event.set('[vpn][tunnel_type]', event.get('[vpn][tunnel_type][tunnel_type]'))"
}
ruby {
  code => "event.set('[vpn][tunnel_id]', event.get('[vpn][tunnel_type][tunnel_id]'))"
}
ruby {
  code => "event.set('[vpn][tunnel_ip]', event.get('[vpn][tunnel_type][tunnel_ip]'))"
}

```

or can I condense them all into a single call of the ruby filter with three codes specified:

```auto
ruby {
  code => "event.set('[vpn][tunnel_type]', event.get('[vpn][tunnel_type][tunnel_type]'))"
  code => "event.set('[vpn][tunnel_id]', event.get('[vpn][tunnel_type][tunnel_id]'))"
  code => "event.set('[vpn][tunnel_ip]', event.get('[vpn][tunnel_type][tunnel_ip]'))"
}

```

---

<div class="post-metadata">

**Author:** ![Badger](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/badger/32/25190_2.png) [@Badger](https://discuss.elastic.co/u/Badger)\
**Post date:** [February 23, 2021, 6:42pm UTC](https://discuss.elastic.co/t/json-parsing-issue/265219/4 "2021-02-23T18:42:20Z")

</div>

> [@wwalker](#):
>
> `code => "event.set('[vpn][tunnel_type]', event.get('[vpn][tunnel_type][tunnel_type]'))"`

Once you overwrite [vpn][tunnel\_type] you can no longer reference the other fields in it. If the names of the fields are fixed you can use mutate

```
mutate {
    rename => {
        "[vpn][tunnel_type][tunnel_ip]" => "[vpn][tunnel_ip]"
        "[vpn][tunnel_type][tunnel_id]" => "[vpn][tunnel_id]"
    }
}
mutate {
    rename => {
        "[vpn][tunnel_type][tunnel_type]" => "[vpn][tunnel_type]"
    }
}

```

I believe it would work if you merged those two, provided "[vpn][tunnel\_type][tunnel\_type]" was listed last, but I do not think logstash provides a guarantee of that. Doing it in two filters should guarantee it.

---

<div class="post-metadata">

**Author:** ![wwalker](https://avatars.discourse-cdn.com/v4/letter/w/43a26b/32.png) [@wwalker](https://discuss.elastic.co/u/wwalker)\
**Post date:** [February 23, 2021, 6:54pm UTC](https://discuss.elastic.co/t/json-parsing-issue/265219/5 "2021-02-23T18:54:13Z")

</div>

I scrapped everything that was in the pipeline for this event and started from scratch. I don't know why JSON filter was ever used as the data comes in structured as key/value pairs. It also looks like mutate's rename filter was being invoked to rename the nested duplicate tunnel\_type up a level...but that wasn't working for some reason. What I got to work was using ruby to pull the information up a level and then delete the original nested field:

```auto
ruby {
        code => "event.set('[vpn][tunnel_id]', event.get('[vpn][tunnel_type][tunnel_id]'))"
          remove_field => [
            "[vpn][tunnel_type][tunnel_id]"
          ]
      }
      ruby {
        code => "event.set('[vpn][tunnel_ip]', event.get('[vpn][tunnel_type][tunnel_ip]'))"
          remove_field => [
            "[vpn][tunnel_type][tunnel_ip]"
          ]
      }
      ruby {
        code => "event.set('[vpn][tunnel_type]', event.get('[vpn][tunnel_type][tunnel_type]'))"
          remove_field => [
            "[vpn][tunnel_type][tunnel_type]"
          ]
      }

```

I probably need to put some logic in to ensure that a given field is present before executing one of these ruby filters. However, in the absence of a value, the key/value pair is still present as `tunnel_type=`.

Regardless, you helped put me on the right path, so much appreciated for the help @Badger

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [March 23, 2021, 6:54pm UTC](https://discuss.elastic.co/t/json-parsing-issue/265219/6 "2021-03-23T18:54:25Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
