# Ruby filter to pack string value into object

**URL:** <https://discuss.elastic.co/t/ruby-filter-to-pack-string-value-into-object/346854>\
**Category:** Logstash\
**Created:** [November 10, 2023, 9:35am UTC](https://discuss.elastic.co/t/ruby-filter-to-pack-string-value-into-object/346854 "2023-11-10T09:35:54Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![rcz](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/rcz/32/59428_2.png) [@rcz](https://discuss.elastic.co/u/rcz)\
**Post date:** [November 10, 2023, 9:35am UTC](https://discuss.elastic.co/t/ruby-filter-to-pack-string-value-into-object/346854/1 "2023-11-10T09:35:54Z")

</div>

I have a client that sends HTTP request events with a nested structure, like:

```auto
context.response.body
context.response.code
context.response.headers.Content-Length
context.response.headers.Content-Type
etc..

```

But _sometimes_ the `context.response` field is sent as a string, which is a problem for Elasticsearch.  
I want to make a Ruby filter to fix this, so if it's a string, pack it into `context.response.body` instead.

This is what I came up with initially (having never written any Ruby before):

```ruby
if event.include? '[context][response]' && event.get('[context][response]').is_a? String
        textval = event.get('[context][response]')
        event.remove('[context][response]')
        event.set('[context][response][body]', textval)
end

```

Logstash just crashes immediately, with the error:

```auto
SyntaxError: (ruby filter code):3: syntax error, unexpected tCONSTANT                   
if event.include? '[context][response]' && event.get('[context][response]').is_a? String
^

```

Any help is greatly appreciated 🙂

---

<div class="post-metadata">

**Author:** ![grumo35](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/grumo35/32/59451_2.png) [@grumo35](https://discuss.elastic.co/u/grumo35)\
**Post date:** [November 10, 2023, 9:56am UTC](https://discuss.elastic.co/t/ruby-filter-to-pack-string-value-into-object/346854/2 "2023-11-10T09:56:59Z")

</div>

Hi,

If you have any field type issues i'd recommend to use the convert plugin in logstash ? [Mutate filter plugin | Logstash Reference [8.11] | Elastic](https://www.elastic.co/guide/en/logstash/current/plugins-filters-mutate.html#plugins-filters-mutate-convert)

does this fit your use case ?

---

<div class="post-metadata">

**Author:** ![rcz](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/rcz/32/59428_2.png) [@rcz](https://discuss.elastic.co/u/rcz)\
**Post date:** [November 10, 2023, 9:59am UTC](https://discuss.elastic.co/t/ruby-filter-to-pack-string-value-into-object/346854/3 "2023-11-10T09:59:13Z")

</div>

Yes, that actually fits it perfectly!

I didn't realize it would just "do nothing" if run on a hash. Thank you!

**EDIT:** Sorry, was too quick.  
The `convert` process can't turn a string into a hash, as far as I can see.  
The issue is I need to check:

```plaintext
if context.response is type String:
  move context.response into context.response.body

```

Moving it into a different field would also be acceptable, but most of the events contain `context.response` as a hash, so those need to be left untouched.

---

<div class="post-metadata">

**Author:** ![leandrojmp](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/leandrojmp/32/107231_2.png) [@leandrojmp](https://discuss.elastic.co/u/leandrojmp)\
**Post date:** [November 10, 2023, 12:47pm UTC](https://discuss.elastic.co/t/ruby-filter-to-pack-string-value-into-object/346854/4 "2023-11-10T12:47:26Z")

</div>

When `context.response` is an object is there any nested field that is **always** present? Like will you always have `context.response.body` or `context.response.code`?

If so, than you can fix this issue without the need to write any ruby, just combining some mutate filters.

---

<div class="post-metadata">

**Author:** ![rcz](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/rcz/32/59428_2.png) [@rcz](https://discuss.elastic.co/u/rcz)\
**Post date:** [November 10, 2023, 1:03pm UTC](https://discuss.elastic.co/t/ruby-filter-to-pack-string-value-into-object/346854/5 "2023-11-10T13:03:45Z")

</div>

Yes, it will always have those fields when it's an object.  
Which mutate filters? How can I detect when it's an object/string?

Edit: Also still interested in why the Ruby code is failing

---

<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:** [November 10, 2023, 1:38pm UTC](https://discuss.elastic.co/t/ruby-filter-to-pack-string-value-into-object/346854/6 "2023-11-10T13:38:48Z")

</div>

That looks a lot like [this](https://discuss.elastic.co/t/unexpected-tconstant-in-ruby-script/346709).

---

<div class="post-metadata">

**Author:** ![rcz](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/rcz/32/59428_2.png) [@rcz](https://discuss.elastic.co/u/rcz)\
**Post date:** [November 10, 2023, 1:48pm UTC](https://discuss.elastic.co/t/ruby-filter-to-pack-string-value-into-object/346854/7 "2023-11-10T13:48:13Z")

</div>

Not sure why, but the new code works:

```ruby
if event.include? '[context][response]' and event.get('[context][response]').is_a? String
  event.set('[context][response][body]', event.remove('[context][response]'))
end

```

Thank you!

---

<div class="post-metadata">

**Author:** ![leandrojmp](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/leandrojmp/32/107231_2.png) [@leandrojmp](https://discuss.elastic.co/u/leandrojmp)\
**Post date:** [November 10, 2023, 2:17pm UTC](https://discuss.elastic.co/t/ruby-filter-to-pack-string-value-into-object/346854/8 "2023-11-10T14:17:09Z")

</div>

> [@rcz](#):
>
> Yes, it will always have those fields when it's an object.  
> Which mutate filters? How can I detect when it's an object/string?

If you always have a specific field when the field is an object you can text if this field exists, if it does not exist, than you do not have it as an object.

For example, using this sample events:

```auto
{ "context": { "response": "response_is_string"}}
{ "context": { "response": {"body": "response_is_hash"}}}

```

The following `filter` will work:

```auto
filter {
    json {
        source => "message"
    }
    if ![context][response][body] {
        mutate {
            rename => {
                "[context][response]" => "[context][response][body]"
            }
        }
    }

}

```

It tests if the field `context.response.body` exists, if it does not exists than it will rename `context.response` to `context.response.body`, but this only works if you can guarantee that when `context.response` is an object, it will always have the nested field `body`.

---

<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:** [December 8, 2023, 2:17pm UTC](https://discuss.elastic.co/t/ruby-filter-to-pack-string-value-into-object/346854/9 "2023-12-08T14:17:55Z")

</div>

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