# Custom Unpack for configuration

**URL:** <https://discuss.elastic.co/t/custom-unpack-for-configuration/254306>\
**Category:** Beats\
**Tags:** libbeat\
**Created:** [November 4, 2020, 4:34pm UTC](https://discuss.elastic.co/t/custom-unpack-for-configuration/254306 "2020-11-04T16:34:52Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![tomkirk](https://avatars.discourse-cdn.com/v4/letter/t/76d3ee/32.png) [@tomkirk](https://discuss.elastic.co/u/tomkirk)\
**Post date:** [November 4, 2020, 4:34pm UTC](https://discuss.elastic.co/t/custom-unpack-for-configuration/254306/1 "2020-11-04T16:34:52Z")

</div>

I'm working on a beat where I have currently in my configuration an array of string like this:

```
fields:
  - FieldName
  - AnotherFieldName

```

What I would like is the ability to optionally provide a `type` tag, like so:

```
fields:
    - FieldName
    - name: AnotherFieldName
    - type: int

```

Essentially I want to define my configuration structure so that if it is a string it uses that as the name parameter of my struct, otherwise it reads the `name` and `type` tags. A field is defined like this:

```auto
type Field struct {
    Name string 'config:"name"`
    Type string 'config:"type"`
}

```

and the config like this:

```auto
type Config struct {
    Fields []Field `config:"fields"`
}

```

I had considered implementing the `Unpacker` interface for a `Field`, checking if it was a string and setting the name, but then I wanted to call the default `Unpack` for the struct if it wasn't a string but I can't work out how to do this.

Is there a way of either

1. Defining the conversion with tags
2. calling the default Unpack for the field

Thanks

---

<div class="post-metadata">

**Author:** ![marc.guasch](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/marc.guasch/32/74642_2.png) [@marc.guasch](https://discuss.elastic.co/u/marc.guasch)\
**Post date:** [November 5, 2020, 10:27am UTC](https://discuss.elastic.co/t/custom-unpack-for-configuration/254306/2 "2020-11-05T10:27:28Z")

</div>

Hello @tomkirk,

As you mention, you can implement the Unpacker interface. If I understood what you try to achieve correctly, I think you might not need to fallback to the original Unpack method with something like:

```
type cfg struct {
    Fields []field `config:"fields"`
}

type field struct {
    Name string `config:"name"`
    Type string `config:"type"`
}

func (f *field) Unpack(v interface{}) error {
	switch tv := v.(type) {
	case string:
		*f = field{
			Name: tv,
		}
	case map[string]interface{}:
		n, _ := tv["name"].(string)
		t, _ := tv["type"].(string)
        // additional checks if needed
		*f = field{
			Name: n,
			Type: t,
		}
	default:
		return errors.New("unexpected type")
	}
	return nil
}

```

Hope it helps!

---

<div class="post-metadata">

**Author:** ![tomkirk](https://avatars.discourse-cdn.com/v4/letter/t/76d3ee/32.png) [@tomkirk](https://discuss.elastic.co/u/tomkirk)\
**Post date:** [November 5, 2020, 10:31am UTC](https://discuss.elastic.co/t/custom-unpack-for-configuration/254306/3 "2020-11-05T10:31:22Z")

</div>

Thanks for your reply.

The reason why I wanted to fallback to the original `Unpack` was to prevent the need to explicitly check each field. I was hoping that I could just use the `config` tags to do it for me. That way if I want another parameter in the future I can define it like the other configuration settings. Is that not possible?

---

<div class="post-metadata">

**Author:** ![marc.guasch](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/marc.guasch/32/74642_2.png) [@marc.guasch](https://discuss.elastic.co/u/marc.guasch)\
**Post date:** [November 5, 2020, 10:52am UTC](https://discuss.elastic.co/t/custom-unpack-for-configuration/254306/4 "2020-11-05T10:52:45Z")

</div>

It is possible, in that case you will need to embed your field type in another one used just to do the Unpack, otherwise you will end up having a stack overflow from recursive Unpack calls:

```
type cfg struct {
	Fields []cfgfield `config:"fields"`
}

type cfgfield struct {
	field
}
    
type field struct {
	Name string `config:"name"`
	Type string `config:"type"`
}

func (f *cfgfield) Unpack(v interface{}) error {
	switch tv := v.(type) {
	case string:
		*f = cfgfield{
			field: field{
				Name: tv,
			},
		}
	default:
		cfg, err := ucfg.NewFrom(v)
		if err != nil {
			return err
		}
		field := field{}
		if err := cfg.Unpack(&field); err != nil {
			return err
		}
		*f = cfgfield{field: field}
	}
	return nil
}

```

Hope it helps 🙂

---

<div class="post-metadata">

**Author:** ![tomkirk](https://avatars.discourse-cdn.com/v4/letter/t/76d3ee/32.png) [@tomkirk](https://discuss.elastic.co/u/tomkirk)\
**Post date:** [November 5, 2020, 11:01am UTC](https://discuss.elastic.co/t/custom-unpack-for-configuration/254306/5 "2020-11-05T11:01:24Z")

</div>

That looks like what I need. How would I go about getting access to the `ucfg` package inside my beat? The one I am working on isn't using go modules, but `glide`. I currently have my `glide.yaml` as:

```auto
package: .
import:
- package: github.com/elastic/beats
  version: v7.1.1
  subpackages:
  - /libbeat/beat
  - libbeat/cfgfile
  - libbeat/common
  - libbeat/logp

```

Is there a way to use the ucfg that is used inside that version of libbeat?

Thanks

---

<div class="post-metadata">

**Author:** ![marc.guasch](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/marc.guasch/32/74642_2.png) [@marc.guasch](https://discuss.elastic.co/u/marc.guasch)\
**Post date:** [November 5, 2020, 11:15am UTC](https://discuss.elastic.co/t/custom-unpack-for-configuration/254306/6 "2020-11-05T11:15:05Z")

</div>

I am not sure if that is what you mean, but ucfg refers to elastic/go-ucfg which is a module of its own [https://github.com/elastic/go-ucfg](https://github.com/elastic/go-ucfg) so I guess by adding it as another imported package should do the trick.

---

<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 3, 2020, 1:15pm UTC](https://discuss.elastic.co/t/custom-unpack-for-configuration/254306/7 "2020-12-03T13:15:09Z")

</div>

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