diff --git a/.chloggen/ottl-function-factory-interface.yaml b/.chloggen/ottl-function-factory-interface.yaml
new file mode 100755
index 000000000000..c8b2e5be501d
--- /dev/null
+++ b/.chloggen/ottl-function-factory-interface.yaml
@@ -0,0 +1,18 @@
+# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
+change_type: breaking
+
+# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
+component: pkg/ottl
+
+# A brief description of the change.  Surround your text with quotes ("") if it needs to start with a backtick (`).
+note: Reimplement all OTTL function factories to implement the `ottl.Factory` interface.
+
+# One or more tracking issues related to the change
+issues: [14712]
+
+# (Optional) One or more lines of additional information to render under the primary note.
+# These lines will be padded with 2 spaces and then inserted directly into the document.
+# Use pipe (|) for multiline entries.
+subtext: |
+  The `ottl.Factory` interface allows making factories extendable and defines
+  canonical names for the functions across components using the OTTL.
\ No newline at end of file
diff --git a/internal/filter/filterottl/filter.go b/internal/filter/filterottl/filter.go
index 7f30dca0ddd8..0516831405d4 100644
--- a/internal/filter/filterottl/filter.go
+++ b/internal/filter/filterottl/filter.go
@@ -32,9 +32,10 @@ import (
 // NewBoolExprForSpan creates a BoolExpr[ottlspan.TransformContext] that will return true if any of the given OTTL conditions evaluate to true.
 // The passed in functions should use the ottlspan.TransformContext.
 // If a function named `drop` is not present in the function map it will be added automatically so that parsing works as expected
-func NewBoolExprForSpan(conditions []string, functions map[string]interface{}, errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottlspan.TransformContext], error) {
-	if _, ok := functions["drop"]; !ok {
-		functions["drop"] = drop[ottlspan.TransformContext]
+func NewBoolExprForSpan(conditions []string, functions map[string]ottl.Factory[ottlspan.TransformContext], errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottlspan.TransformContext], error) {
+	drop := newDropFactory[ottlspan.TransformContext]()
+	if _, ok := functions[drop.Name()]; !ok {
+		functions[drop.Name()] = drop
 	}
 	statmentsStr := conditionsToStatements(conditions)
 	parser, err := ottlspan.NewParser(functions, set)
@@ -52,9 +53,10 @@ func NewBoolExprForSpan(conditions []string, functions map[string]interface{}, e
 // NewBoolExprForSpanEvent creates a BoolExpr[ottlspanevent.TransformContext] that will return true if any of the given OTTL conditions evaluate to true.
 // The passed in functions should use the ottlspanevent.TransformContext.
 // If a function named `drop` is not present in the function map it will be added automatically so that parsing works as expected
-func NewBoolExprForSpanEvent(conditions []string, functions map[string]interface{}, errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottlspanevent.TransformContext], error) {
-	if _, ok := functions["drop"]; !ok {
-		functions["drop"] = drop[ottlspanevent.TransformContext]
+func NewBoolExprForSpanEvent(conditions []string, functions map[string]ottl.Factory[ottlspanevent.TransformContext], errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottlspanevent.TransformContext], error) {
+	drop := newDropFactory[ottlspanevent.TransformContext]()
+	if _, ok := functions[drop.Name()]; !ok {
+		functions[drop.Name()] = drop
 	}
 	statmentsStr := conditionsToStatements(conditions)
 	parser, err := ottlspanevent.NewParser(functions, set)
@@ -72,9 +74,10 @@ func NewBoolExprForSpanEvent(conditions []string, functions map[string]interface
 // NewBoolExprForMetric creates a BoolExpr[ottlmetric.TransformContext] that will return true if any of the given OTTL conditions evaluate to true.
 // The passed in functions should use the ottlmetric.TransformContext.
 // If a function named `drop` is not present in the function map it will be added automatically so that parsing works as expected
-func NewBoolExprForMetric(conditions []string, functions map[string]interface{}, errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottlmetric.TransformContext], error) {
-	if _, ok := functions["drop"]; !ok {
-		functions["drop"] = drop[ottlmetric.TransformContext]
+func NewBoolExprForMetric(conditions []string, functions map[string]ottl.Factory[ottlmetric.TransformContext], errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottlmetric.TransformContext], error) {
+	drop := newDropFactory[ottlmetric.TransformContext]()
+	if _, ok := functions[drop.Name()]; !ok {
+		functions[drop.Name()] = drop
 	}
 	statmentsStr := conditionsToStatements(conditions)
 	parser, err := ottlmetric.NewParser(functions, set)
@@ -92,9 +95,10 @@ func NewBoolExprForMetric(conditions []string, functions map[string]interface{},
 // NewBoolExprForDataPoint creates a BoolExpr[ottldatapoint.TransformContext] that will return true if any of the given OTTL conditions evaluate to true.
 // The passed in functions should use the ottldatapoint.TransformContext.
 // If a function named `drop` is not present in the function map it will be added automatically so that parsing works as expected
-func NewBoolExprForDataPoint(conditions []string, functions map[string]interface{}, errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottldatapoint.TransformContext], error) {
-	if _, ok := functions["drop"]; !ok {
-		functions["drop"] = drop[ottldatapoint.TransformContext]
+func NewBoolExprForDataPoint(conditions []string, functions map[string]ottl.Factory[ottldatapoint.TransformContext], errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottldatapoint.TransformContext], error) {
+	drop := newDropFactory[ottldatapoint.TransformContext]()
+	if _, ok := functions[drop.Name()]; !ok {
+		functions[drop.Name()] = drop
 	}
 	statmentsStr := conditionsToStatements(conditions)
 	parser, err := ottldatapoint.NewParser(functions, set)
@@ -112,9 +116,10 @@ func NewBoolExprForDataPoint(conditions []string, functions map[string]interface
 // NewBoolExprForLog creates a BoolExpr[ottllog.TransformContext] that will return true if any of the given OTTL conditions evaluate to true.
 // The passed in functions should use the ottllog.TransformContext.
 // If a function named `drop` is not present in the function map it will be added automatically so that parsing works as expected
-func NewBoolExprForLog(conditions []string, functions map[string]interface{}, errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottllog.TransformContext], error) {
-	if _, ok := functions["drop"]; !ok {
-		functions["drop"] = drop[ottllog.TransformContext]
+func NewBoolExprForLog(conditions []string, functions map[string]ottl.Factory[ottllog.TransformContext], errorMode ottl.ErrorMode, set component.TelemetrySettings) (expr.BoolExpr[ottllog.TransformContext], error) {
+	drop := newDropFactory[ottllog.TransformContext]()
+	if _, ok := functions[drop.Name()]; !ok {
+		functions[drop.Name()] = drop
 	}
 	statmentsStr := conditionsToStatements(conditions)
 	parser, err := ottllog.NewParser(functions, set)
@@ -137,41 +142,49 @@ func conditionsToStatements(conditions []string) []string {
 	return statements
 }
 
-func StandardSpanFuncs() map[string]interface{} {
+func StandardSpanFuncs() map[string]ottl.Factory[ottlspan.TransformContext] {
 	return standardFuncs[ottlspan.TransformContext]()
 }
 
-func StandardSpanEventFuncs() map[string]interface{} {
+func StandardSpanEventFuncs() map[string]ottl.Factory[ottlspanevent.TransformContext] {
 	return standardFuncs[ottlspanevent.TransformContext]()
 }
 
-func StandardMetricFuncs() map[string]interface{} {
+func StandardMetricFuncs() map[string]ottl.Factory[ottlmetric.TransformContext] {
 	return standardFuncs[ottlmetric.TransformContext]()
 }
 
-func StandardDataPointFuncs() map[string]interface{} {
+func StandardDataPointFuncs() map[string]ottl.Factory[ottldatapoint.TransformContext] {
 	return standardFuncs[ottldatapoint.TransformContext]()
 }
 
-func StandardLogFuncs() map[string]interface{} {
+func StandardLogFuncs() map[string]ottl.Factory[ottllog.TransformContext] {
 	return standardFuncs[ottllog.TransformContext]()
 }
 
-func standardFuncs[K any]() map[string]interface{} {
-	return map[string]interface{}{
-		"TraceID":     ottlfuncs.TraceID[K],
-		"SpanID":      ottlfuncs.SpanID[K],
-		"IsMatch":     ottlfuncs.IsMatch[K],
-		"Concat":      ottlfuncs.Concat[K],
-		"Split":       ottlfuncs.Split[K],
-		"Int":         ottlfuncs.Int[K],
-		"ConvertCase": ottlfuncs.ConvertCase[K],
-		"Substring":   ottlfuncs.Substring[K],
-		"drop":        drop[K],
-	}
+func standardFuncs[K any]() map[string]ottl.Factory[K] {
+	return ottl.CreateFactoryMap(
+		ottlfuncs.NewTraceIDFactory[K](),
+		ottlfuncs.NewSpanIDFactory[K](),
+		ottlfuncs.NewIsMatchFactory[K](),
+		ottlfuncs.NewConcatFactory[K](),
+		ottlfuncs.NewSplitFactory[K](),
+		ottlfuncs.NewIntFactory[K](),
+		ottlfuncs.NewConvertCaseFactory[K](),
+		ottlfuncs.NewSubstringFactory[K](),
+		newDropFactory[K](),
+	)
+}
+
+func newDropFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("drop", nil, createDropFunction[K])
+}
+
+func createDropFunction[K any](_ ottl.FunctionContext, _ ottl.Arguments) (ottl.ExprFunc[K], error) {
+	return dropFn[K]()
 }
 
-func drop[K any]() (ottl.ExprFunc[K], error) {
+func dropFn[K any]() (ottl.ExprFunc[K], error) {
 	return func(context.Context, K) (interface{}, error) {
 		return true, nil
 	}, nil
diff --git a/pkg/ottl/boolean_value_test.go b/pkg/ottl/boolean_value_test.go
index 7e5648d86cdd..dcb4e1e53ca6 100644
--- a/pkg/ottl/boolean_value_test.go
+++ b/pkg/ottl/boolean_value_test.go
@@ -80,7 +80,7 @@ func comparisonHelper(left any, right any, op string) *comparison {
 }
 
 func Test_newComparisonEvaluator(t *testing.T) {
-	p, _ := NewParser[any](
+	p, _ := NewParser(
 		defaultFunctionsForTests(),
 		testParsePath,
 		componenttest.NewNopTelemetrySettings(),
@@ -131,7 +131,7 @@ func Test_newComparisonEvaluator(t *testing.T) {
 }
 
 func Test_newConditionEvaluator_invalid(t *testing.T) {
-	p, _ := NewParser[any](
+	p, _ := NewParser(
 		defaultFunctionsForTests(),
 		testParsePath,
 		componenttest.NewNopTelemetrySettings(),
@@ -163,23 +163,23 @@ func Test_newConditionEvaluator_invalid(t *testing.T) {
 	}
 }
 
-func True[K any]() (ExprFunc[K], error) {
-	return func(ctx context.Context, tCtx K) (interface{}, error) {
+func True() (ExprFunc[any], error) {
+	return func(ctx context.Context, tCtx any) (interface{}, error) {
 		return true, nil
 	}, nil
 }
-func False[K any]() (ExprFunc[K], error) {
-	return func(ctx context.Context, tCtx K) (interface{}, error) {
+func False() (ExprFunc[any], error) {
+	return func(ctx context.Context, tCtx any) (interface{}, error) {
 		return false, nil
 	}, nil
 }
 
 func Test_newBooleanExpressionEvaluator(t *testing.T) {
 	functions := defaultFunctionsForTests()
-	functions["True"] = True[any]
-	functions["False"] = False[any]
+	functions["True"] = createFactory("True", &struct{}{}, True)
+	functions["False"] = createFactory("False", &struct{}{}, False)
 
-	p, _ := NewParser[any](
+	p, _ := NewParser(
 		functions,
 		testParsePath,
 		componenttest.NewNopTelemetrySettings(),
@@ -560,9 +560,9 @@ func Test_newBooleanExpressionEvaluator(t *testing.T) {
 }
 
 func Test_newBooleanExpressionEvaluator_invalid(t *testing.T) {
-	functions := map[string]interface{}{"Hello": hello[interface{}]}
+	functions := map[string]Factory[any]{"Hello": createFactory("Hello", &struct{}{}, hello)}
 
-	p, _ := NewParser[any](
+	p, _ := NewParser(
 		functions,
 		testParsePath,
 		componenttest.NewNopTelemetrySettings(),
diff --git a/pkg/ottl/contexts/ottldatapoint/datapoint.go b/pkg/ottl/contexts/ottldatapoint/datapoint.go
index 1db3a4e73ed2..f0ee9fac8a01 100644
--- a/pkg/ottl/contexts/ottldatapoint/datapoint.go
+++ b/pkg/ottl/contexts/ottldatapoint/datapoint.go
@@ -77,7 +77,7 @@ func (tCtx TransformContext) getCache() pcommon.Map {
 	return tCtx.cache
 }
 
-func NewParser(functions map[string]interface{}, telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
+func NewParser(functions map[string]ottl.Factory[TransformContext], telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
 	p, err := ottl.NewParser[TransformContext](
 		functions,
 		parsePath,
diff --git a/pkg/ottl/contexts/ottllog/log.go b/pkg/ottl/contexts/ottllog/log.go
index 42b22e6ffdea..cdad23e34420 100644
--- a/pkg/ottl/contexts/ottllog/log.go
+++ b/pkg/ottl/contexts/ottllog/log.go
@@ -66,7 +66,7 @@ func (tCtx TransformContext) getCache() pcommon.Map {
 	return tCtx.cache
 }
 
-func NewParser(functions map[string]interface{}, telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
+func NewParser(functions map[string]ottl.Factory[TransformContext], telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
 	p, err := ottl.NewParser[TransformContext](
 		functions,
 		parsePath,
diff --git a/pkg/ottl/contexts/ottlmetric/metrics.go b/pkg/ottl/contexts/ottlmetric/metrics.go
index 7538eb40dbf4..4d611c53e4cb 100644
--- a/pkg/ottl/contexts/ottlmetric/metrics.go
+++ b/pkg/ottl/contexts/ottlmetric/metrics.go
@@ -65,7 +65,7 @@ func (tCtx TransformContext) getCache() pcommon.Map {
 	return tCtx.cache
 }
 
-func NewParser(functions map[string]interface{}, telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
+func NewParser(functions map[string]ottl.Factory[TransformContext], telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
 	p, err := ottl.NewParser[TransformContext](
 		functions,
 		parsePath,
diff --git a/pkg/ottl/contexts/ottlresource/resource.go b/pkg/ottl/contexts/ottlresource/resource.go
index e28bcc875525..346d76e55567 100644
--- a/pkg/ottl/contexts/ottlresource/resource.go
+++ b/pkg/ottl/contexts/ottlresource/resource.go
@@ -50,7 +50,7 @@ func (tCtx TransformContext) getCache() pcommon.Map {
 	return tCtx.cache
 }
 
-func NewParser(functions map[string]interface{}, telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
+func NewParser(functions map[string]ottl.Factory[TransformContext], telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
 	p, err := ottl.NewParser[TransformContext](
 		functions,
 		parsePath,
diff --git a/pkg/ottl/contexts/ottlscope/scope.go b/pkg/ottl/contexts/ottlscope/scope.go
index c32fb2833b32..c60dfea720a9 100644
--- a/pkg/ottl/contexts/ottlscope/scope.go
+++ b/pkg/ottl/contexts/ottlscope/scope.go
@@ -57,7 +57,7 @@ func (tCtx TransformContext) getCache() pcommon.Map {
 	return tCtx.cache
 }
 
-func NewParser(functions map[string]interface{}, telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
+func NewParser(functions map[string]ottl.Factory[TransformContext], telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
 	p, err := ottl.NewParser[TransformContext](
 		functions,
 		parsePath,
diff --git a/pkg/ottl/contexts/ottlspan/span.go b/pkg/ottl/contexts/ottlspan/span.go
index ef7571248edc..190d62b366f6 100644
--- a/pkg/ottl/contexts/ottlspan/span.go
+++ b/pkg/ottl/contexts/ottlspan/span.go
@@ -64,7 +64,7 @@ func (tCtx TransformContext) getCache() pcommon.Map {
 	return tCtx.cache
 }
 
-func NewParser(functions map[string]interface{}, telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
+func NewParser(functions map[string]ottl.Factory[TransformContext], telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
 	p, err := ottl.NewParser[TransformContext](
 		functions,
 		parsePath,
diff --git a/pkg/ottl/contexts/ottlspanevent/span_events.go b/pkg/ottl/contexts/ottlspanevent/span_events.go
index 99b601339cbf..0b8f2eda9d41 100644
--- a/pkg/ottl/contexts/ottlspanevent/span_events.go
+++ b/pkg/ottl/contexts/ottlspanevent/span_events.go
@@ -72,7 +72,7 @@ func (tCtx TransformContext) getCache() pcommon.Map {
 	return tCtx.cache
 }
 
-func NewParser(functions map[string]interface{}, telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
+func NewParser(functions map[string]ottl.Factory[TransformContext], telemetrySettings component.TelemetrySettings, options ...Option) (ottl.Parser[TransformContext], error) {
 	p, err := ottl.NewParser[TransformContext](
 		functions,
 		parsePath,
diff --git a/pkg/ottl/expression_test.go b/pkg/ottl/expression_test.go
index 0cd4ce646cfb..06a164e15e77 100644
--- a/pkg/ottl/expression_test.go
+++ b/pkg/ottl/expression_test.go
@@ -25,8 +25,8 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottltest"
 )
 
-func hello[K any]() (ExprFunc[K], error) {
-	return func(ctx context.Context, tCtx K) (interface{}, error) {
+func hello() (ExprFunc[any], error) {
+	return func(ctx context.Context, tCtx any) (any, error) {
 		return "world", nil
 	}, nil
 }
@@ -289,7 +289,7 @@ func Test_newGetter(t *testing.T) {
 		},
 	}
 
-	functions := map[string]interface{}{"Hello": hello[interface{}]}
+	functions := CreateFactoryMap(createFactory("Hello", &struct{}{}, hello))
 
 	p, _ := NewParser[any](
 		functions,
diff --git a/pkg/ottl/factory.go b/pkg/ottl/factory.go
new file mode 100644
index 000000000000..77678a0f1b97
--- /dev/null
+++ b/pkg/ottl/factory.go
@@ -0,0 +1,96 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ottl // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
+
+import "go.opentelemetry.io/collector/component"
+
+// Arguments holds the arguments for an OTTL function, with arguments
+// specified as fields on a struct. Argument ordering is defined
+type Arguments interface{}
+
+// FunctionContext contains data provided by the Collector
+// component to the OTTL for use in functions.
+type FunctionContext struct {
+	Set component.TelemetrySettings
+}
+
+// Factory defines an OTTL function factory that will generate an OTTL
+// function to be called based on an invocation within a statement.
+type Factory[K any] interface {
+	// Name is the canonical name to be used by the user when invocating
+	// the function generated by this Factory.
+	Name() string
+
+	// CreateDefaultArguments initializes an Arguments struct specific to this
+	// Factory containing the arguments for the function.
+	CreateDefaultArguments() Arguments
+
+	// CreateFunction creates an OTTL function that will use the given Arguments.
+	CreateFunction(fCtx FunctionContext, args Arguments) (ExprFunc[K], error)
+
+	// Disallow implementations outside this package.
+	unexportedFactoryFunc()
+}
+
+type CreateFunctionFunc[K any] func(fCtx FunctionContext, args Arguments) (ExprFunc[K], error)
+
+type factory[K any] struct {
+	name               string
+	args               Arguments
+	createFunctionFunc CreateFunctionFunc[K]
+}
+
+// nolint:unused
+func (f *factory[K]) unexportedFactoryFunc() {}
+
+func (f *factory[K]) Name() string {
+	return f.name
+}
+
+func (f *factory[K]) CreateDefaultArguments() Arguments {
+	return f.args
+}
+
+func (f *factory[K]) CreateFunction(fCtx FunctionContext, args Arguments) (ExprFunc[K], error) {
+	return f.createFunctionFunc(fCtx, args)
+}
+
+type FactoryOption[K any] func(factory *factory[K])
+
+func NewFactory[K any](name string, args Arguments, createFunctionFunc CreateFunctionFunc[K], options ...FactoryOption[K]) Factory[K] {
+	f := &factory[K]{
+		name:               name,
+		args:               args,
+		createFunctionFunc: createFunctionFunc,
+	}
+
+	for _, option := range options {
+		option(f)
+	}
+
+	return f
+}
+
+// CreateFactoryMap takes a list of factories and returns a map of Factories
+// keyed on their canonical names.
+func CreateFactoryMap[K any](factories ...Factory[K]) map[string]Factory[K] {
+	factoryMap := map[string]Factory[K]{}
+
+	for _, fn := range factories {
+		factoryMap[fn.Name()] = fn
+	}
+
+	return factoryMap
+}
diff --git a/pkg/ottl/functions.go b/pkg/ottl/functions.go
index a5d903c2b7e2..f14efff22960 100644
--- a/pkg/ottl/functions.go
+++ b/pkg/ottl/functions.go
@@ -18,6 +18,7 @@ import (
 	"errors"
 	"fmt"
 	"reflect"
+	"strconv"
 	"strings"
 
 	"go.opentelemetry.io/collector/pdata/pcommon"
@@ -34,65 +35,74 @@ func (p *Parser[K]) newFunctionCall(inv invocation) (Expr[K], error) {
 	if !ok {
 		return Expr[K]{}, fmt.Errorf("undefined function %v", inv.Function)
 	}
-	args, err := p.buildArgs(inv, reflect.TypeOf(f))
+	args := f.CreateDefaultArguments()
+
+	// A nil value indicates the function takes no arguments.
+	if args != nil {
+		// Pointer values are necessary to fulfill the Go reflection
+		// settability requirements. Non-pointer values are not
+		// modifiable through reflection.
+		if reflect.TypeOf(args).Kind() != reflect.Pointer {
+			return Expr[K]{}, fmt.Errorf("factory for %s must return a pointer to an Arguments value in its CreateDefaultArguments method", inv.Function)
+		}
+
+		err := p.buildArgs(inv, reflect.ValueOf(args).Elem())
+		if err != nil {
+			return Expr[K]{}, fmt.Errorf("error while parsing arguments for call to '%v': %w", inv.Function, err)
+		}
+	}
+
+	fn, err := f.CreateFunction(FunctionContext{Set: p.telemetrySettings}, args)
 	if err != nil {
-		return Expr[K]{}, fmt.Errorf("error while parsing arguments for call to '%v': %w", inv.Function, err)
+		return Expr[K]{}, fmt.Errorf("couldn't create function: %w", err)
 	}
 
-	returnVals := reflect.ValueOf(f).Call(args)
+	return Expr[K]{exprFunc: fn}, err
+}
 
-	if returnVals[1].IsNil() {
-		err = nil
-	} else {
-		err = returnVals[1].Interface().(error)
+func (p *Parser[K]) buildArgs(inv invocation, argsVal reflect.Value) error {
+	if len(inv.Arguments) != argsVal.NumField() {
+		return fmt.Errorf("incorrect number of arguments. Expected: %d Received: %d", argsVal.NumField(), len(inv.Arguments))
 	}
 
-	return Expr[K]{exprFunc: returnVals[0].Interface().(ExprFunc[K])}, err
-}
+	argsType := argsVal.Type()
+
+	for i := 0; i < argsVal.NumField(); i++ {
+		field := argsVal.Field(i)
+		fieldType := field.Type()
+
+		fieldTag, ok := argsType.Field(i).Tag.Lookup("ottlarg")
 
-func (p *Parser[K]) buildArgs(inv invocation, fType reflect.Type) ([]reflect.Value, error) {
-	var args []reflect.Value
-	// Some function arguments may be intended to take values from the calling processor
-	// instead of being passed by the caller of the OTTL function, so we have to keep
-	// track of the index of the argument passed within the DSL.
-	// e.g. TelemetrySettings, which is provided by the processor to the OTTL Parser struct.
-	DSLArgumentIndex := 0
-	for i := 0; i < fType.NumIn(); i++ {
-		argType := fType.In(i)
-
-		arg, isInternalArg := p.buildInternalArg(argType)
-		if isInternalArg {
-			args = append(args, reflect.ValueOf(arg))
-			continue
+		if !ok {
+			return fmt.Errorf("no `ottlarg` struct tag on Arguments field '%s'", argsType.Field(i).Name)
+		}
+
+		argNum, err := strconv.Atoi(fieldTag)
+
+		if err != nil {
+			return fmt.Errorf("ottlarg struct tag on field '%s' is not a valid integer: %w", argsType.Field(i).Name, err)
 		}
 
-		if DSLArgumentIndex >= len(inv.Arguments) {
-			return nil, fmt.Errorf("not enough arguments")
+		if argNum < 0 || argNum >= len(inv.Arguments) {
+			return fmt.Errorf("ottlarg struct tag on field '%s' has value %d, but must be between 0 and %d", argsType.Field(i).Name, argNum, len(inv.Arguments))
 		}
 
-		argVal := inv.Arguments[DSLArgumentIndex]
+		argVal := inv.Arguments[argNum]
 
 		var val any
-		var err error
-		if argType.Kind() == reflect.Slice {
-			val, err = p.buildSliceArg(argVal, argType)
+		if fieldType.Kind() == reflect.Slice {
+			val, err = p.buildSliceArg(argVal, fieldType)
 		} else {
-			val, err = p.buildArg(argVal, argType)
+			val, err = p.buildArg(argVal, fieldType)
 		}
 
 		if err != nil {
-			return nil, fmt.Errorf("invalid argument at position %v: %w", DSLArgumentIndex, err)
+			return fmt.Errorf("invalid argument at position %v: %w", i, err)
 		}
-		args = append(args, reflect.ValueOf(val))
-
-		DSLArgumentIndex++
+		field.Set(reflect.ValueOf(val))
 	}
 
-	if len(inv.Arguments) > DSLArgumentIndex {
-		return nil, fmt.Errorf("too many arguments")
-	}
-
-	return args, nil
+	return nil
 }
 
 func (p *Parser[K]) buildSliceArg(argVal value, argType reflect.Type) (any, error) {
@@ -226,15 +236,6 @@ func (p *Parser[K]) buildArg(argVal value, argType reflect.Type) (any, error) {
 	}
 }
 
-// Handle interfaces that can be declared as parameters to a OTTL function, but will
-// never be called in an invocation. Returns whether the arg is an internal arg.
-func (p *Parser[K]) buildInternalArg(argType reflect.Type) (any, bool) {
-	if argType.Name() == "TelemetrySettings" {
-		return p.telemetrySettings, true
-	}
-	return nil, false
-}
-
 type buildArgFunc func(value, reflect.Type) (any, error)
 
 func buildSlice[T any](argVal value, argType reflect.Type, buildArg buildArgFunc, name string) (any, error) {
diff --git a/pkg/ottl/functions_test.go b/pkg/ottl/functions_test.go
index 880502bd2832..fdf4581847a3 100644
--- a/pkg/ottl/functions_test.go
+++ b/pkg/ottl/functions_test.go
@@ -17,28 +17,91 @@ package ottl
 import (
 	"context"
 	"errors"
+	"fmt"
+	"reflect"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-	"go.opentelemetry.io/collector/component"
 	"go.opentelemetry.io/collector/component/componenttest"
 
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottltest"
 )
 
 func Test_NewFunctionCall_invalid(t *testing.T) {
-	functions := make(map[string]interface{})
-	functions["testing_error"] = functionThatHasAnError
-	functions["testing_getsetter"] = functionWithGetSetter
-	functions["testing_getter"] = functionWithGetter
-	functions["testing_multiple_args"] = functionWithMultipleArgs
-	functions["testing_string"] = functionWithString
-	functions["testing_string_slice"] = functionWithStringSlice
-	functions["testing_byte_slice"] = functionWithByteSlice
-	functions["testing_enum"] = functionWithEnum
-	functions["testing_telemetry_settings_first"] = functionWithTelemetrySettingsFirst
-
-	p, _ := NewParser[any](
+	functions := CreateFactoryMap(
+		createFactory(
+			"testing_error",
+			&errorFunctionArguments{},
+			functionThatHasAnError,
+		),
+		createFactory[any](
+			"testing_getsetter",
+			&getSetterArguments{},
+			functionWithGetSetter,
+		),
+		createFactory[any](
+			"testing_getter",
+			&getterArguments{},
+			functionWithGetter,
+		),
+		createFactory[any](
+			"testing_multiple_args",
+			&multipleArgsArguments{},
+			functionWithMultipleArgs,
+		),
+		createFactory[any](
+			"testing_string",
+			&stringArguments{},
+			functionWithString,
+		),
+		createFactory(
+			"testing_string_slice",
+			&stringSliceArguments{},
+			functionWithStringSlice,
+		),
+		createFactory(
+			"testing_byte_slice",
+			&byteSliceArguments{},
+			functionWithByteSlice,
+		),
+		createFactory[any](
+			"testing_enum",
+			&enumArguments{},
+			functionWithEnum,
+		),
+		createFactory(
+			"non_pointer",
+			errorFunctionArguments{},
+			functionThatHasAnError,
+		),
+		createFactory(
+			"no_struct_tag",
+			&noStructTagFunctionArguments{},
+			functionThatHasAnError,
+		),
+		createFactory(
+			"wrong_struct_tag",
+			&wrongTagFunctionArguments{},
+			functionThatHasAnError,
+		),
+		createFactory(
+			"bad_struct_tag",
+			&badStructTagFunctionArguments{},
+			functionThatHasAnError,
+		),
+		createFactory(
+			"negative_struct_tag",
+			&negativeStructTagFunctionArguments{},
+			functionThatHasAnError,
+		),
+		createFactory(
+			"out_of_bounds_struct_tag",
+			&outOfBoundsStructTagFunctionArguments{},
+			functionThatHasAnError,
+		),
+	)
+
+	p, _ := NewParser(
 		functions,
 		testParsePath,
 		componenttest.NewNopTelemetrySettings(),
@@ -259,18 +322,80 @@ func Test_NewFunctionCall_invalid(t *testing.T) {
 				},
 			},
 		},
+		{
+			name: "factory definition uses a non-pointer Arguments value",
+			inv: invocation{
+				Function: "non_pointer",
+			},
+		},
+		{
+			name: "no struct tags",
+			inv: invocation{
+				Function: "no_struct_tag",
+				Arguments: []value{
+					{
+						String: ottltest.Strp("str"),
+					},
+				},
+			},
+		},
+		{
+			name: "using the wrong struct tag",
+			inv: invocation{
+				Function: "wrong_struct_tag",
+				Arguments: []value{
+					{
+						String: ottltest.Strp("str"),
+					},
+				},
+			},
+		},
+		{
+			name: "non-integer struct tags",
+			inv: invocation{
+				Function: "bad_struct_tag",
+				Arguments: []value{
+					{
+						String: ottltest.Strp("str"),
+					},
+				},
+			},
+		},
+		{
+			name: "struct tag index too low",
+			inv: invocation{
+				Function: "negative_struct_tag",
+				Arguments: []value{
+					{
+						String: ottltest.Strp("str"),
+					},
+				},
+			},
+		},
+		{
+			name: "struct tag index too high",
+			inv: invocation{
+				Function: "out_of_bounds_struct_tag",
+				Arguments: []value{
+					{
+						String: ottltest.Strp("str"),
+					},
+				},
+			},
+		},
 	}
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			_, err := p.newFunctionCall(tt.inv)
+			t.Log(err)
 			assert.Error(t, err)
 		})
 	}
 }
 
 func Test_NewFunctionCall(t *testing.T) {
-	p, _ := NewParser[any](
+	p, _ := NewParser(
 		defaultFunctionsForTests(),
 		testParsePath,
 		componenttest.NewNopTelemetrySettings(),
@@ -282,6 +407,20 @@ func Test_NewFunctionCall(t *testing.T) {
 		inv  invocation
 		want any
 	}{
+		{
+			name: "no arguments",
+			inv: invocation{
+				Function: "testing_noop",
+				Arguments: []value{
+					{
+						List: &list{
+							Values: []value{},
+						},
+					},
+				},
+			},
+			want: nil,
+		},
 		{
 			name: "empty slice arg",
 			inv: invocation{
@@ -872,84 +1011,6 @@ func Test_NewFunctionCall(t *testing.T) {
 			},
 			want: nil,
 		},
-		{
-			name: "telemetrySettings first",
-			inv: invocation{
-				Function: "testing_telemetry_settings_first",
-				Arguments: []value{
-					{
-						String: ottltest.Strp("test0"),
-					},
-					{
-						List: &list{
-							Values: []value{
-								{
-									String: ottltest.Strp("test"),
-								},
-							},
-						},
-					},
-					{
-						Literal: &mathExprLiteral{
-							Int: ottltest.Intp(1),
-						},
-					},
-				},
-			},
-			want: nil,
-		},
-		{
-			name: "telemetrySettings middle",
-			inv: invocation{
-				Function: "testing_telemetry_settings_middle",
-				Arguments: []value{
-					{
-						String: ottltest.Strp("test0"),
-					},
-					{
-						List: &list{
-							Values: []value{
-								{
-									String: ottltest.Strp("test"),
-								},
-							},
-						},
-					},
-					{
-						Literal: &mathExprLiteral{
-							Int: ottltest.Intp(1),
-						},
-					},
-				},
-			},
-			want: nil,
-		},
-		{
-			name: "telemetrySettings last",
-			inv: invocation{
-				Function: "testing_telemetry_settings_last",
-				Arguments: []value{
-					{
-						String: ottltest.Strp("test0"),
-					},
-					{
-						List: &list{
-							Values: []value{
-								{
-									String: ottltest.Strp("test"),
-								},
-							},
-						},
-					},
-					{
-						Literal: &mathExprLiteral{
-							Int: ottltest.Intp(1),
-						},
-					},
-				},
-			},
-			want: nil,
-		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -964,126 +1025,217 @@ func Test_NewFunctionCall(t *testing.T) {
 	}
 }
 
-func functionWithStringSlice(strs []string) (ExprFunc[interface{}], error) {
-	return func(context.Context, interface{}) (interface{}, error) {
+func functionWithNoArguments() (ExprFunc[any], error) {
+	return func(context.Context, any) (any, error) {
+		return nil, nil
+	}, nil
+}
+
+type stringSliceArguments struct {
+	Strings []string `ottlarg:"0"`
+}
+
+func functionWithStringSlice(strs []string) (ExprFunc[any], error) {
+	return func(context.Context, any) (any, error) {
 		return len(strs), nil
 	}, nil
 }
 
+type floatSliceArguments struct {
+	Floats []float64 `ottlarg:"0"`
+}
+
 func functionWithFloatSlice(floats []float64) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return len(floats), nil
 	}, nil
 }
 
+type intSliceArguments struct {
+	Ints []int64 `ottlarg:"0"`
+}
+
 func functionWithIntSlice(ints []int64) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return len(ints), nil
 	}, nil
 }
 
+type byteSliceArguments struct {
+	Bytes []byte `ottlarg:"0"`
+}
+
 func functionWithByteSlice(bytes []byte) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return len(bytes), nil
 	}, nil
 }
 
+type getterSliceArguments struct {
+	Getters []Getter[any] `ottlarg:"0"`
+}
+
 func functionWithGetterSlice(getters []Getter[interface{}]) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return len(getters), nil
 	}, nil
 }
 
-func functionWithStringGetterSlice(getters []Getter[interface{}]) (ExprFunc[interface{}], error) {
+type stringGetterSliceArguments struct {
+	StringGetters []StringGetter[any] `ottlarg:"0"`
+}
+
+func functionWithStringGetterSlice(getters []StringGetter[interface{}]) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return len(getters), nil
 	}, nil
 }
 
+type pMapGetterSliceArguments struct {
+	PMapGetters []PMapGetter[any] `ottlarg:"0"`
+}
+
 func functionWithPMapGetterSlice(getters []PMapGetter[interface{}]) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return len(getters), nil
 	}, nil
 }
 
+type stringLikeGetterSliceArguments struct {
+	StringLikeGetters []StringLikeGetter[any] `ottlarg:"0"`
+}
+
 func functionWithStringLikeGetterSlice(getters []StringLikeGetter[interface{}]) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return len(getters), nil
 	}, nil
 }
 
+type setterArguments struct {
+	SetterArg Setter[any] `ottlarg:"0"`
+}
+
 func functionWithSetter(Setter[interface{}]) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type getSetterArguments struct {
+	GetSetterArg GetSetter[any] `ottlarg:"0"`
+}
+
 func functionWithGetSetter(GetSetter[interface{}]) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type getterArguments struct {
+	GetterArg Getter[any] `ottlarg:"0"`
+}
+
 func functionWithGetter(Getter[interface{}]) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type stringGetterArguments struct {
+	StringGetterArg StringGetter[any] `ottlarg:"0"`
+}
+
 func functionWithStringGetter(StringGetter[interface{}]) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type stringLikeGetterArguments struct {
+	StringLikeGetterArg StringLikeGetter[any] `ottlarg:"0"`
+}
+
 func functionWithStringLikeGetter(StringLikeGetter[interface{}]) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type intGetterArguments struct {
+	IntGetterArg IntGetter[any] `ottlarg:"0"`
+}
+
 func functionWithIntGetter(IntGetter[interface{}]) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type pMapGetterArguments struct {
+	PMapArg PMapGetter[any] `ottlarg:"0"`
+}
+
 func functionWithPMapGetter(PMapGetter[interface{}]) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type stringArguments struct {
+	StringArg string `ottlarg:"0"`
+}
+
 func functionWithString(string) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type floatArguments struct {
+	FloatArg float64 `ottlarg:"0"`
+}
+
 func functionWithFloat(float64) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type intArguments struct {
+	IntArg int64 `ottlarg:"0"`
+}
+
 func functionWithInt(int64) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type boolArguments struct {
+	BoolArg bool `ottlarg:"0"`
+}
+
 func functionWithBool(bool) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type multipleArgsArguments struct {
+	GetSetterArg GetSetter[any] `ottlarg:"0"`
+	StringArg    string         `ottlarg:"1"`
+	FloatArg     float64        `ottlarg:"2"`
+	IntArg       int64          `ottlarg:"3"`
+}
+
 func functionWithMultipleArgs(GetSetter[interface{}], string, float64, int64) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
+type errorFunctionArguments struct{}
+
 func functionThatHasAnError() (ExprFunc[interface{}], error) {
 	err := errors.New("testing")
 	return func(context.Context, interface{}) (interface{}, error) {
@@ -1091,55 +1243,182 @@ func functionThatHasAnError() (ExprFunc[interface{}], error) {
 	}, err
 }
 
+type enumArguments struct {
+	EnumArg Enum `ottlarg:"0"`
+}
+
 func functionWithEnum(Enum) (ExprFunc[interface{}], error) {
 	return func(context.Context, interface{}) (interface{}, error) {
 		return "anything", nil
 	}, nil
 }
 
-func functionWithTelemetrySettingsFirst(component.TelemetrySettings, string, []string, int64) (ExprFunc[interface{}], error) {
-	return func(context.Context, interface{}) (interface{}, error) {
-		return "anything", nil
-	}, nil
+type noStructTagFunctionArguments struct {
+	StringArg string
 }
 
-func functionWithTelemetrySettingsMiddle(string, []string, component.TelemetrySettings, int64) (ExprFunc[interface{}], error) {
-	return func(context.Context, interface{}) (interface{}, error) {
-		return "anything", nil
-	}, nil
+type badStructTagFunctionArguments struct {
+	StringArg string `ottlarg:"a"`
 }
 
-func functionWithTelemetrySettingsLast(string, []string, int64, component.TelemetrySettings) (ExprFunc[interface{}], error) {
-	return func(context.Context, interface{}) (interface{}, error) {
-		return "anything", nil
-	}, nil
+type negativeStructTagFunctionArguments struct {
+	StringArg string `ottlarg:"-1"`
 }
 
-func defaultFunctionsForTests() map[string]interface{} {
-	functions := make(map[string]interface{})
-	functions["testing_string_slice"] = functionWithStringSlice
-	functions["testing_float_slice"] = functionWithFloatSlice
-	functions["testing_int_slice"] = functionWithIntSlice
-	functions["testing_byte_slice"] = functionWithByteSlice
-	functions["testing_getter_slice"] = functionWithGetterSlice
-	functions["testing_stringgetter_slice"] = functionWithStringGetterSlice
-	functions["testing_pmapgetter_slice"] = functionWithPMapGetterSlice
-	functions["testing_stringlikegetter_slice"] = functionWithStringLikeGetterSlice
-	functions["testing_setter"] = functionWithSetter
-	functions["testing_getsetter"] = functionWithGetSetter
-	functions["testing_getter"] = functionWithGetter
-	functions["testing_stringgetter"] = functionWithStringGetter
-	functions["testing_stringlikegetter"] = functionWithStringLikeGetter
-	functions["testing_intgetter"] = functionWithIntGetter
-	functions["testing_pmapgetter"] = functionWithPMapGetter
-	functions["testing_string"] = functionWithString
-	functions["testing_float"] = functionWithFloat
-	functions["testing_int"] = functionWithInt
-	functions["testing_bool"] = functionWithBool
-	functions["testing_multiple_args"] = functionWithMultipleArgs
-	functions["testing_enum"] = functionWithEnum
-	functions["testing_telemetry_settings_first"] = functionWithTelemetrySettingsFirst
-	functions["testing_telemetry_settings_middle"] = functionWithTelemetrySettingsMiddle
-	functions["testing_telemetry_settings_last"] = functionWithTelemetrySettingsLast
-	return functions
+type outOfBoundsStructTagFunctionArguments struct {
+	StringArg string `ottlarg:"1"`
+}
+
+type wrongTagFunctionArguments struct {
+	StringArg string `argument:"1"`
+}
+
+func createFactory[A any](name string, args A, fn any) Factory[any] {
+	createFunction := func(fCtx FunctionContext, oArgs Arguments) (ExprFunc[any], error) {
+		fArgs, ok := oArgs.(A)
+
+		if !ok {
+			return nil, fmt.Errorf("createFactory args must be of type %T", fArgs)
+		}
+
+		funcVal := reflect.ValueOf(fn)
+
+		if funcVal.Kind() != reflect.Func {
+			return nil, fmt.Errorf("a non-function value was passed to createFactory")
+		}
+
+		argsVal := reflect.ValueOf(fArgs).Elem()
+		fnArgs := make([]reflect.Value, argsVal.NumField())
+
+		for i := 0; i < argsVal.NumField(); i++ {
+			fnArgs[i] = argsVal.Field(i)
+		}
+
+		out := funcVal.Call(fnArgs)
+
+		if !out[1].IsNil() {
+			return out[0].Interface().(ExprFunc[any]), out[1].Interface().(error)
+		}
+
+		return out[0].Interface().(ExprFunc[any]), nil
+	}
+
+	return NewFactory(name, args, createFunction)
+}
+
+func defaultFunctionsForTests() map[string]Factory[any] {
+	return CreateFactoryMap(
+		NewFactory(
+			"testing_noop",
+			nil,
+			func(FunctionContext, Arguments) (ExprFunc[any], error) {
+				return functionWithNoArguments()
+			},
+		),
+		createFactory(
+			"testing_string_slice",
+			&stringSliceArguments{},
+			functionWithStringSlice,
+		),
+		createFactory(
+			"testing_float_slice",
+			&floatSliceArguments{},
+			functionWithFloatSlice,
+		),
+		createFactory(
+			"testing_int_slice",
+			&intSliceArguments{},
+			functionWithIntSlice,
+		),
+		createFactory(
+			"testing_byte_slice",
+			&byteSliceArguments{},
+			functionWithByteSlice,
+		),
+		createFactory[any](
+			"testing_getter_slice",
+			&getterSliceArguments{},
+			functionWithGetterSlice,
+		),
+		createFactory[any](
+			"testing_stringgetter_slice",
+			&stringGetterSliceArguments{},
+			functionWithStringGetterSlice,
+		),
+		createFactory[any](
+			"testing_stringlikegetter_slice",
+			&stringLikeGetterSliceArguments{},
+			functionWithStringLikeGetterSlice,
+		),
+		createFactory[any](
+			"testing_pmapgetter_slice",
+			&pMapGetterSliceArguments{},
+			functionWithPMapGetterSlice,
+		),
+		createFactory[any](
+			"testing_setter",
+			&setterArguments{},
+			functionWithSetter,
+		),
+		createFactory[any](
+			"testing_getsetter",
+			&getSetterArguments{},
+			functionWithGetSetter,
+		),
+		createFactory[any](
+			"testing_getter",
+			&getterArguments{},
+			functionWithGetter,
+		),
+		createFactory[any](
+			"testing_stringgetter",
+			&stringGetterArguments{},
+			functionWithStringGetter,
+		),
+		createFactory[any](
+			"testing_stringlikegetter",
+			&stringLikeGetterArguments{},
+			functionWithStringLikeGetter,
+		),
+		createFactory[any](
+			"testing_intgetter",
+			&intGetterArguments{},
+			functionWithIntGetter,
+		),
+		createFactory[any](
+			"testing_pmapgetter",
+			&pMapGetterArguments{},
+			functionWithPMapGetter,
+		),
+		createFactory[any](
+			"testing_string",
+			&stringArguments{},
+			functionWithString,
+		),
+		createFactory[any](
+			"testing_float",
+			&floatArguments{},
+			functionWithFloat,
+		),
+		createFactory[any](
+			"testing_int",
+			&intArguments{},
+			functionWithInt,
+		),
+		createFactory[any](
+			"testing_bool",
+			&boolArguments{},
+			functionWithBool,
+		),
+		createFactory[any](
+			"testing_multiple_args",
+			&multipleArgsArguments{},
+			functionWithMultipleArgs,
+		),
+		createFactory[any](
+			"testing_enum",
+			&enumArguments{},
+			functionWithEnum,
+		),
+	)
 }
diff --git a/pkg/ottl/math_test.go b/pkg/ottl/math_test.go
index 34746ba726b4..89c1367649fa 100644
--- a/pkg/ottl/math_test.go
+++ b/pkg/ottl/math_test.go
@@ -67,6 +67,10 @@ func threePointOne[K any]() (ExprFunc[K], error) {
 	}, nil
 }
 
+type sumArguments struct {
+	Ints []int64 `ottlarg:"0"`
+}
+
 //nolint:unparam
 func sum[K any](ints []int64) (ExprFunc[K], error) {
 	return func(context.Context, K) (interface{}, error) {
@@ -206,12 +210,12 @@ func Test_evaluateMathExpression(t *testing.T) {
 		},
 	}
 
-	functions := map[string]interface{}{
-		"One":           one[any],
-		"Two":           two[any],
-		"ThreePointOne": threePointOne[any],
-		"Sum":           sum[any],
-	}
+	functions := CreateFactoryMap(
+		createFactory("One", &struct{}{}, one[any]),
+		createFactory("Two", &struct{}{}, two[any]),
+		createFactory("ThreePointOne", &struct{}{}, threePointOne[any]),
+		createFactory("Sum", &sumArguments{}, sum[any]),
+	)
 
 	p, _ := NewParser[any](
 		functions,
@@ -249,12 +253,12 @@ func Test_evaluateMathExpression_error(t *testing.T) {
 		},
 	}
 
-	functions := map[string]interface{}{
-		"one":           one[any],
-		"two":           two[any],
-		"threePointOne": threePointOne[any],
-		"sum":           sum[any],
-	}
+	functions := CreateFactoryMap(
+		createFactory("one", &struct{}{}, one[any]),
+		createFactory("two", &struct{}{}, two[any]),
+		createFactory("threePointOne", &struct{}{}, threePointOne[any]),
+		createFactory("sum", &sumArguments{}, sum[any]),
+	)
 
 	p, _ := NewParser[any](
 		functions,
diff --git a/pkg/ottl/ottlfuncs/func_concat.go b/pkg/ottl/ottlfuncs/func_concat.go
index 3244d594abff..d2cf0dd5f941 100644
--- a/pkg/ottl/ottlfuncs/func_concat.go
+++ b/pkg/ottl/ottlfuncs/func_concat.go
@@ -22,7 +22,26 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func Concat[K any](vals []ottl.StringLikeGetter[K], delimiter string) (ottl.ExprFunc[K], error) {
+type ConcatArguments[K any] struct {
+	Vals      []ottl.StringLikeGetter[K] `ottlarg:"0"`
+	Delimiter string                     `ottlarg:"1"`
+}
+
+func NewConcatFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("Concat", &ConcatArguments[K]{}, createConcatFunction[K])
+}
+
+func createConcatFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*ConcatArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("ConcatFactory args must be of type *ConcatArguments[K]")
+	}
+
+	return concat(args.Vals, args.Delimiter), nil
+}
+
+func concat[K any](vals []ottl.StringLikeGetter[K], delimiter string) ottl.ExprFunc[K] {
 	return func(ctx context.Context, tCtx K) (interface{}, error) {
 		builder := strings.Builder{}
 		for i, rv := range vals {
@@ -40,5 +59,5 @@ func Concat[K any](vals []ottl.StringLikeGetter[K], delimiter string) (ottl.Expr
 			}
 		}
 		return builder.String(), nil
-	}, nil
+	}
 }
diff --git a/pkg/ottl/ottlfuncs/func_concat_test.go b/pkg/ottl/ottlfuncs/func_concat_test.go
index f3b51d921387..60667aa76897 100644
--- a/pkg/ottl/ottlfuncs/func_concat_test.go
+++ b/pkg/ottl/ottlfuncs/func_concat_test.go
@@ -230,8 +230,7 @@ func Test_concat(t *testing.T) {
 				getters[i] = val
 			}
 
-			exprFunc, err := Concat(getters, tt.delimiter)
-			assert.NoError(t, err)
+			exprFunc := concat(getters, tt.delimiter)
 			result, err := exprFunc(nil, nil)
 			assert.NoError(t, err)
 			assert.Equal(t, tt.expected, result)
@@ -245,8 +244,7 @@ func Test_concat_error(t *testing.T) {
 			return make(chan int), nil
 		},
 	}
-	exprFunc, err := Concat[interface{}]([]ottl.StringLikeGetter[interface{}]{target}, "test")
-	assert.NoError(t, err)
-	_, err = exprFunc(context.Background(), nil)
+	exprFunc := concat[interface{}]([]ottl.StringLikeGetter[interface{}]{target}, "test")
+	_, err := exprFunc(context.Background(), nil)
 	assert.Error(t, err)
 }
diff --git a/pkg/ottl/ottlfuncs/func_convert_case.go b/pkg/ottl/ottlfuncs/func_convert_case.go
index 25d48b8a72e7..e3b06a8ab8c1 100644
--- a/pkg/ottl/ottlfuncs/func_convert_case.go
+++ b/pkg/ottl/ottlfuncs/func_convert_case.go
@@ -24,7 +24,26 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func ConvertCase[K any](target ottl.StringGetter[K], toCase string) (ottl.ExprFunc[K], error) {
+type ConvertCaseArguments[K any] struct {
+	Target ottl.StringGetter[K] `ottlarg:"0"`
+	ToCase string               `ottlarg:"1"`
+}
+
+func NewConvertCaseFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("ConvertCase", &ConvertCaseArguments[K]{}, createConvertCaseFunction[K])
+}
+
+func createConvertCaseFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*ConvertCaseArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("ConvertCaseFactory args must be of type *ConvertCaseArguments[K]")
+	}
+
+	return convertCase(args.Target, args.ToCase)
+}
+
+func convertCase[K any](target ottl.StringGetter[K], toCase string) (ottl.ExprFunc[K], error) {
 	if toCase != "lower" && toCase != "upper" && toCase != "snake" && toCase != "camel" {
 		return nil, fmt.Errorf("invalid case: %s, allowed cases are: lower, upper, snake, camel", toCase)
 	}
diff --git a/pkg/ottl/ottlfuncs/func_convert_case_test.go b/pkg/ottl/ottlfuncs/func_convert_case_test.go
index 74d277709d1f..9126a8c627c0 100644
--- a/pkg/ottl/ottlfuncs/func_convert_case_test.go
+++ b/pkg/ottl/ottlfuncs/func_convert_case_test.go
@@ -188,7 +188,7 @@ func Test_convertCase(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			exprFunc, err := ConvertCase(tt.target, tt.toCase)
+			exprFunc, err := convertCase(tt.target, tt.toCase)
 			assert.NoError(t, err)
 			result, err := exprFunc(nil, nil)
 			assert.NoError(t, err)
@@ -215,7 +215,7 @@ func Test_convertCaseError(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			_, err := ConvertCase(tt.target, tt.toCase)
+			_, err := convertCase(tt.target, tt.toCase)
 			require.Error(t, err)
 			assert.ErrorContains(t, err, "invalid case: unset, allowed cases are: lower, upper, snake, camel")
 		})
@@ -252,7 +252,7 @@ func Test_convertCaseRuntimeError(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			exprFunc, err := ConvertCase[any](tt.target, tt.toCase)
+			exprFunc, err := convertCase[any](tt.target, tt.toCase)
 			require.NoError(t, err)
 			_, err = exprFunc(context.Background(), nil)
 			assert.ErrorContains(t, err, tt.expectedError)
diff --git a/pkg/ottl/ottlfuncs/func_delete_key.go b/pkg/ottl/ottlfuncs/func_delete_key.go
index 1ed51675b002..0ba0f86b52ec 100644
--- a/pkg/ottl/ottlfuncs/func_delete_key.go
+++ b/pkg/ottl/ottlfuncs/func_delete_key.go
@@ -16,11 +16,31 @@ package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-c
 
 import (
 	"context"
+	"fmt"
 
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func DeleteKey[K any](target ottl.PMapGetter[K], key string) (ottl.ExprFunc[K], error) {
+type DeleteKeyArguments[K any] struct {
+	Target ottl.PMapGetter[K] `ottlarg:"0"`
+	Key    string             `ottlarg:"1"`
+}
+
+func NewDeleteKeyFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("delete_key", &DeleteKeyArguments[K]{}, createDeleteKeyFunction[K])
+}
+
+func createDeleteKeyFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*DeleteKeyArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("DeleteKeysFactory args must be of type *DeleteKeyArguments[K]")
+	}
+
+	return deleteKey(args.Target, args.Key), nil
+}
+
+func deleteKey[K any](target ottl.PMapGetter[K], key string) ottl.ExprFunc[K] {
 	return func(ctx context.Context, tCtx K) (interface{}, error) {
 		val, err := target.Get(ctx, tCtx)
 		if err != nil {
@@ -28,5 +48,5 @@ func DeleteKey[K any](target ottl.PMapGetter[K], key string) (ottl.ExprFunc[K],
 		}
 		val.Remove(key)
 		return nil, nil
-	}, nil
+	}
 }
diff --git a/pkg/ottl/ottlfuncs/func_delete_key_test.go b/pkg/ottl/ottlfuncs/func_delete_key_test.go
index ad20e9a1994f..3d65fe7a2329 100644
--- a/pkg/ottl/ottlfuncs/func_delete_key_test.go
+++ b/pkg/ottl/ottlfuncs/func_delete_key_test.go
@@ -76,10 +76,9 @@ func Test_deleteKey(t *testing.T) {
 			scenarioMap := pcommon.NewMap()
 			input.CopyTo(scenarioMap)
 
-			exprFunc, err := DeleteKey(tt.target, tt.key)
-			assert.NoError(t, err)
+			exprFunc := deleteKey(tt.target, tt.key)
 
-			_, err = exprFunc(nil, scenarioMap)
+			_, err := exprFunc(nil, scenarioMap)
 			assert.Nil(t, err)
 
 			expected := pcommon.NewMap()
@@ -100,9 +99,8 @@ func Test_deleteKey_bad_input(t *testing.T) {
 
 	key := "anything"
 
-	exprFunc, err := DeleteKey[interface{}](target, key)
-	assert.NoError(t, err)
-	_, err = exprFunc(nil, input)
+	exprFunc := deleteKey[interface{}](target, key)
+	_, err := exprFunc(nil, input)
 	assert.Error(t, err)
 }
 
@@ -115,8 +113,7 @@ func Test_deleteKey_get_nil(t *testing.T) {
 
 	key := "anything"
 
-	exprFunc, err := DeleteKey[interface{}](target, key)
-	assert.NoError(t, err)
-	_, err = exprFunc(nil, nil)
+	exprFunc := deleteKey[interface{}](target, key)
+	_, err := exprFunc(nil, nil)
 	assert.Error(t, err)
 }
diff --git a/pkg/ottl/ottlfuncs/func_delete_matching_keys.go b/pkg/ottl/ottlfuncs/func_delete_matching_keys.go
index a6f16f178817..a3ae9315584f 100644
--- a/pkg/ottl/ottlfuncs/func_delete_matching_keys.go
+++ b/pkg/ottl/ottlfuncs/func_delete_matching_keys.go
@@ -24,7 +24,26 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func DeleteMatchingKeys[K any](target ottl.PMapGetter[K], pattern string) (ottl.ExprFunc[K], error) {
+type DeleteMatchingKeysArguments[K any] struct {
+	Target  ottl.PMapGetter[K] `ottlarg:"0"`
+	Pattern string             `ottlarg:"1"`
+}
+
+func NewDeleteMatchingKeysFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("delete_matching_keys", &DeleteMatchingKeysArguments[K]{}, createDeleteMatchingKeysFunction[K])
+}
+
+func createDeleteMatchingKeysFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*DeleteMatchingKeysArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("DeleteMatchingKeysFactory args must be of type *DeleteMatchingKeysArguments[K]")
+	}
+
+	return deleteMatchingKeys(args.Target, args.Pattern)
+}
+
+func deleteMatchingKeys[K any](target ottl.PMapGetter[K], pattern string) (ottl.ExprFunc[K], error) {
 	compiledPattern, err := regexp.Compile(pattern)
 	if err != nil {
 		return nil, fmt.Errorf("the regex pattern supplied to delete_matching_keys is not a valid pattern: %w", err)
diff --git a/pkg/ottl/ottlfuncs/func_delete_matching_keys_test.go b/pkg/ottl/ottlfuncs/func_delete_matching_keys_test.go
index 45041e5e5084..4e7a58c5994a 100644
--- a/pkg/ottl/ottlfuncs/func_delete_matching_keys_test.go
+++ b/pkg/ottl/ottlfuncs/func_delete_matching_keys_test.go
@@ -75,7 +75,7 @@ func Test_deleteMatchingKeys(t *testing.T) {
 			scenarioMap := pcommon.NewMap()
 			input.CopyTo(scenarioMap)
 
-			exprFunc, err := DeleteMatchingKeys(tt.target, tt.pattern)
+			exprFunc, err := deleteMatchingKeys(tt.target, tt.pattern)
 			assert.NoError(t, err)
 
 			_, err = exprFunc(nil, scenarioMap)
@@ -97,7 +97,7 @@ func Test_deleteMatchingKeys_bad_input(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := DeleteMatchingKeys[interface{}](target, "anything")
+	exprFunc, err := deleteMatchingKeys[interface{}](target, "anything")
 	assert.NoError(t, err)
 
 	_, err = exprFunc(nil, input)
@@ -111,7 +111,7 @@ func Test_deleteMatchingKeys_get_nil(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := DeleteMatchingKeys[interface{}](target, "anything")
+	exprFunc, err := deleteMatchingKeys[interface{}](target, "anything")
 	assert.NoError(t, err)
 	_, err = exprFunc(nil, nil)
 	assert.Error(t, err)
@@ -126,7 +126,7 @@ func Test_deleteMatchingKeys_invalid_pattern(t *testing.T) {
 	}
 
 	invalidRegexPattern := "*"
-	_, err := DeleteMatchingKeys[interface{}](target, invalidRegexPattern)
+	_, err := deleteMatchingKeys[interface{}](target, invalidRegexPattern)
 	require.Error(t, err)
 	assert.ErrorContains(t, err, "error parsing regexp:")
 }
diff --git a/pkg/ottl/ottlfuncs/func_int.go b/pkg/ottl/ottlfuncs/func_int.go
index b53beeac52f7..ad216f3e3e32 100644
--- a/pkg/ottl/ottlfuncs/func_int.go
+++ b/pkg/ottl/ottlfuncs/func_int.go
@@ -16,12 +16,31 @@ package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-c
 
 import (
 	"context"
+	"fmt"
 	"strconv"
 
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func Int[K any](target ottl.Getter[K]) (ottl.ExprFunc[K], error) {
+type IntArguments[K any] struct {
+	Target ottl.Getter[K] `ottlarg:"0"`
+}
+
+func NewIntFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("Int", &IntArguments[K]{}, createIntFunction[K])
+}
+
+func createIntFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*IntArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("IntFactory args must be of type *IntArguments[K]")
+	}
+
+	return intFunc(args.Target), nil
+}
+
+func intFunc[K any](target ottl.Getter[K]) ottl.ExprFunc[K] {
 	return func(ctx context.Context, tCtx K) (interface{}, error) {
 		value, err := target.Get(ctx, tCtx)
 		if err != nil {
@@ -47,5 +66,5 @@ func Int[K any](target ottl.Getter[K]) (ottl.ExprFunc[K], error) {
 		default:
 			return nil, nil
 		}
-	}, nil
+	}
 }
diff --git a/pkg/ottl/ottlfuncs/func_int_test.go b/pkg/ottl/ottlfuncs/func_int_test.go
index 1d200cc653c0..231bc1debb5b 100644
--- a/pkg/ottl/ottlfuncs/func_int_test.go
+++ b/pkg/ottl/ottlfuncs/func_int_test.go
@@ -82,12 +82,11 @@ func Test_Int(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			exprFunc, err := Int[interface{}](&ottl.StandardGetSetter[interface{}]{
+			exprFunc := intFunc[interface{}](&ottl.StandardGetSetter[interface{}]{
 				Getter: func(context.Context, interface{}) (interface{}, error) {
 					return tt.value, nil
 				},
 			})
-			assert.NoError(t, err)
 			result, err := exprFunc(nil, nil)
 			assert.NoError(t, err)
 			assert.Equal(t, tt.expected, result)
diff --git a/pkg/ottl/ottlfuncs/func_is_match.go b/pkg/ottl/ottlfuncs/func_is_match.go
index 03e2e2fac460..6ab35ae82215 100644
--- a/pkg/ottl/ottlfuncs/func_is_match.go
+++ b/pkg/ottl/ottlfuncs/func_is_match.go
@@ -22,7 +22,26 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func IsMatch[K any](target ottl.StringLikeGetter[K], pattern string) (ottl.ExprFunc[K], error) {
+type IsMatchArguments[K any] struct {
+	Target  ottl.StringLikeGetter[K] `ottlarg:"0"`
+	Pattern string                   `ottlarg:"1"`
+}
+
+func NewIsMatchFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("IsMatch", &IsMatchArguments[K]{}, createIsMatchFunction[K])
+}
+
+func createIsMatchFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*IsMatchArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("IsMatchFactory args must be of type *IsMatchArguments[K]")
+	}
+
+	return isMatch(args.Target, args.Pattern)
+}
+
+func isMatch[K any](target ottl.StringLikeGetter[K], pattern string) (ottl.ExprFunc[K], error) {
 	compiledPattern, err := regexp.Compile(pattern)
 	if err != nil {
 		return nil, fmt.Errorf("the pattern supplied to IsMatch is not a valid regexp pattern: %w", err)
diff --git a/pkg/ottl/ottlfuncs/func_is_match_test.go b/pkg/ottl/ottlfuncs/func_is_match_test.go
index afa34dbb763f..05ee0a0aecec 100644
--- a/pkg/ottl/ottlfuncs/func_is_match_test.go
+++ b/pkg/ottl/ottlfuncs/func_is_match_test.go
@@ -117,7 +117,7 @@ func Test_isMatch(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			exprFunc, err := IsMatch(tt.target, tt.pattern)
+			exprFunc, err := isMatch(tt.target, tt.pattern)
 			assert.NoError(t, err)
 			result, err := exprFunc(context.Background(), nil)
 			assert.NoError(t, err)
@@ -132,7 +132,7 @@ func Test_isMatch_validation(t *testing.T) {
 			return "anything", nil
 		},
 	}
-	_, err := IsMatch[interface{}](target, "\\K")
+	_, err := isMatch[interface{}](target, "\\K")
 	require.Error(t, err)
 }
 
@@ -142,7 +142,7 @@ func Test_isMatch_error(t *testing.T) {
 			return make(chan int), nil
 		},
 	}
-	exprFunc, err := IsMatch[interface{}](target, "test")
+	exprFunc, err := isMatch[interface{}](target, "test")
 	assert.NoError(t, err)
 	_, err = exprFunc(context.Background(), nil)
 	require.Error(t, err)
diff --git a/pkg/ottl/ottlfuncs/func_keep_keys.go b/pkg/ottl/ottlfuncs/func_keep_keys.go
index be46c87df516..0e680a154037 100644
--- a/pkg/ottl/ottlfuncs/func_keep_keys.go
+++ b/pkg/ottl/ottlfuncs/func_keep_keys.go
@@ -16,13 +16,33 @@ package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-c
 
 import (
 	"context"
+	"fmt"
 
 	"go.opentelemetry.io/collector/pdata/pcommon"
 
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func KeepKeys[K any](target ottl.PMapGetter[K], keys []string) (ottl.ExprFunc[K], error) {
+type KeepKeysArguments[K any] struct {
+	Target ottl.PMapGetter[K] `ottlarg:"0"`
+	Keys   []string           `ottlarg:"1"`
+}
+
+func NewKeepKeysFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("keep_keys", &KeepKeysArguments[K]{}, createKeepKeysFunction[K])
+}
+
+func createKeepKeysFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*KeepKeysArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("KeepKeysFactory args must be of type *KeepKeysArguments[K]")
+	}
+
+	return keepKeys(args.Target, args.Keys), nil
+}
+
+func keepKeys[K any](target ottl.PMapGetter[K], keys []string) ottl.ExprFunc[K] {
 	keySet := make(map[string]struct{}, len(keys))
 	for _, key := range keys {
 		keySet[key] = struct{}{}
@@ -41,5 +61,5 @@ func KeepKeys[K any](target ottl.PMapGetter[K], keys []string) (ottl.ExprFunc[K]
 			val.Clear()
 		}
 		return nil, nil
-	}, nil
+	}
 }
diff --git a/pkg/ottl/ottlfuncs/func_keep_keys_test.go b/pkg/ottl/ottlfuncs/func_keep_keys_test.go
index 87dea8d8041d..8cabedbd49c3 100644
--- a/pkg/ottl/ottlfuncs/func_keep_keys_test.go
+++ b/pkg/ottl/ottlfuncs/func_keep_keys_test.go
@@ -77,10 +77,9 @@ func Test_keepKeys(t *testing.T) {
 			scenarioMap := pcommon.NewMap()
 			input.CopyTo(scenarioMap)
 
-			exprFunc, err := KeepKeys(tt.target, tt.keys)
-			assert.NoError(t, err)
+			exprFunc := keepKeys(tt.target, tt.keys)
 
-			_, err = exprFunc(nil, scenarioMap)
+			_, err := exprFunc(nil, scenarioMap)
 			assert.Nil(t, err)
 
 			expected := pcommon.NewMap()
@@ -101,10 +100,9 @@ func Test_keepKeys_bad_input(t *testing.T) {
 
 	keys := []string{"anything"}
 
-	exprFunc, err := KeepKeys[interface{}](target, keys)
-	assert.NoError(t, err)
+	exprFunc := keepKeys[interface{}](target, keys)
 
-	_, err = exprFunc(nil, input)
+	_, err := exprFunc(nil, input)
 	assert.Error(t, err)
 }
 
@@ -117,8 +115,7 @@ func Test_keepKeys_get_nil(t *testing.T) {
 
 	keys := []string{"anything"}
 
-	exprFunc, err := KeepKeys[interface{}](target, keys)
-	assert.NoError(t, err)
-	_, err = exprFunc(nil, nil)
+	exprFunc := keepKeys[interface{}](target, keys)
+	_, err := exprFunc(nil, nil)
 	assert.Error(t, err)
 }
diff --git a/pkg/ottl/ottlfuncs/func_limit.go b/pkg/ottl/ottlfuncs/func_limit.go
index e34ed23d4d4e..541ffce9c4e3 100644
--- a/pkg/ottl/ottlfuncs/func_limit.go
+++ b/pkg/ottl/ottlfuncs/func_limit.go
@@ -23,7 +23,27 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func Limit[K any](target ottl.PMapGetter[K], limit int64, priorityKeys []string) (ottl.ExprFunc[K], error) {
+type LimitArguments[K any] struct {
+	Target       ottl.PMapGetter[K] `ottlarg:"0"`
+	Limit        int64              `ottlarg:"1"`
+	PriorityKeys []string           `ottlarg:"2"`
+}
+
+func NewLimitFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("Limit", &LimitArguments[K]{}, createLimitFunction[K])
+}
+
+func createLimitFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*LimitArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("LimitFactory args must be of type *LimitArguments[K]")
+	}
+
+	return limit(args.Target, args.Limit, args.PriorityKeys)
+}
+
+func limit[K any](target ottl.PMapGetter[K], limit int64, priorityKeys []string) (ottl.ExprFunc[K], error) {
 	if limit < 0 {
 		return nil, fmt.Errorf("invalid limit for limit function, %d cannot be negative", limit)
 	}
diff --git a/pkg/ottl/ottlfuncs/func_limit_test.go b/pkg/ottl/ottlfuncs/func_limit_test.go
index 0cb14726a415..2bc1ea925d7d 100644
--- a/pkg/ottl/ottlfuncs/func_limit_test.go
+++ b/pkg/ottl/ottlfuncs/func_limit_test.go
@@ -124,7 +124,7 @@ func Test_limit(t *testing.T) {
 			scenarioMap := pcommon.NewMap()
 			input.CopyTo(scenarioMap)
 
-			exprFunc, err := Limit(tt.target, tt.limit, tt.keep)
+			exprFunc, err := limit(tt.target, tt.limit, tt.keep)
 			assert.NoError(t, err)
 
 			result, err := exprFunc(nil, scenarioMap)
@@ -160,7 +160,7 @@ func Test_limit_validation(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			_, err := Limit(tt.target, tt.limit, tt.keep)
+			_, err := limit(tt.target, tt.limit, tt.keep)
 			assert.Error(t, err)
 		})
 	}
@@ -174,7 +174,7 @@ func Test_limit_bad_input(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := Limit[interface{}](target, 1, []string{})
+	exprFunc, err := limit[interface{}](target, 1, []string{})
 	assert.NoError(t, err)
 	_, err = exprFunc(nil, input)
 	assert.Error(t, err)
@@ -187,7 +187,7 @@ func Test_limit_get_nil(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := Limit[interface{}](target, 1, []string{})
+	exprFunc, err := limit[interface{}](target, 1, []string{})
 	assert.NoError(t, err)
 	_, err = exprFunc(nil, nil)
 	assert.Error(t, err)
diff --git a/pkg/ottl/ottlfuncs/func_merge_maps.go b/pkg/ottl/ottlfuncs/func_merge_maps.go
index 9e99b7a8b566..d8bd4249b023 100644
--- a/pkg/ottl/ottlfuncs/func_merge_maps.go
+++ b/pkg/ottl/ottlfuncs/func_merge_maps.go
@@ -29,13 +29,33 @@ const (
 	UPSERT = "upsert"
 )
 
-// MergeMaps function merges the source map into the target map using the supplied strategy to handle conflicts.
+type MergeMapsArguments[K any] struct {
+	Target   ottl.PMapGetter[K] `ottlarg:"0"`
+	Source   ottl.PMapGetter[K] `ottlarg:"1"`
+	Strategy string             `ottlarg:"2"`
+}
+
+func NewMergeMapsFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("merge_maps", &MergeMapsArguments[K]{}, createMergeMapsFunction[K])
+}
+
+func createMergeMapsFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*MergeMapsArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("MergeMapsFactory args must be of type *MergeMapsArguments[K]")
+	}
+
+	return mergeMaps(args.Target, args.Source, args.Strategy)
+}
+
+// mergeMaps function merges the source map into the target map using the supplied strategy to handle conflicts.
 // Strategy definitions:
 //
 //	insert: Insert the value from `source` into `target` where the key does not already exist.
 //	update: Update the entry in `target` with the value from `source` where the key does exist
 //	upsert: Performs insert or update. Insert the value from `source` into `target` where the key does not already exist and update the entry in `target` with the value from `source` where the key does exist.
-func MergeMaps[K any](target ottl.PMapGetter[K], source ottl.PMapGetter[K], strategy string) (ottl.ExprFunc[K], error) {
+func mergeMaps[K any](target ottl.PMapGetter[K], source ottl.PMapGetter[K], strategy string) (ottl.ExprFunc[K], error) {
 	if strategy != INSERT && strategy != UPDATE && strategy != UPSERT {
 		return nil, fmt.Errorf("invalid value for strategy, %v, must be 'insert', 'update' or 'upsert'", strategy)
 	}
diff --git a/pkg/ottl/ottlfuncs/func_merge_maps_test.go b/pkg/ottl/ottlfuncs/func_merge_maps_test.go
index d405dc551637..d1c400acf14e 100644
--- a/pkg/ottl/ottlfuncs/func_merge_maps_test.go
+++ b/pkg/ottl/ottlfuncs/func_merge_maps_test.go
@@ -137,7 +137,7 @@ func Test_MergeMaps(t *testing.T) {
 			scenarioMap := pcommon.NewMap()
 			input.CopyTo(scenarioMap)
 
-			exprFunc, err := MergeMaps[pcommon.Map](targetGetter, tt.source, tt.strategy)
+			exprFunc, err := mergeMaps[pcommon.Map](targetGetter, tt.source, tt.strategy)
 			assert.NoError(t, err)
 
 			result, err := exprFunc(context.Background(), scenarioMap)
@@ -164,7 +164,7 @@ func Test_MergeMaps_bad_target(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := MergeMaps[interface{}](target, input, "insert")
+	exprFunc, err := mergeMaps[interface{}](target, input, "insert")
 	assert.NoError(t, err)
 	_, err = exprFunc(nil, input)
 	assert.Error(t, err)
@@ -182,7 +182,7 @@ func Test_MergeMaps_bad_input(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := MergeMaps[interface{}](target, input, "insert")
+	exprFunc, err := mergeMaps[interface{}](target, input, "insert")
 	assert.NoError(t, err)
 	_, err = exprFunc(nil, input)
 	assert.Error(t, err)
diff --git a/pkg/ottl/ottlfuncs/func_parse_json.go b/pkg/ottl/ottlfuncs/func_parse_json.go
index ae9c5db1c1ef..8f299ede2aea 100644
--- a/pkg/ottl/ottlfuncs/func_parse_json.go
+++ b/pkg/ottl/ottlfuncs/func_parse_json.go
@@ -16,6 +16,7 @@ package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-c
 
 import (
 	"context"
+	"fmt"
 
 	jsoniter "github.com/json-iterator/go"
 	"go.opentelemetry.io/collector/pdata/pcommon"
@@ -23,7 +24,25 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-// ParseJSON returns a `pcommon.Map` struct that is a result of parsing the target string as JSON
+type ParseJSONArguments[K any] struct {
+	Target ottl.StringGetter[K] `ottlarg:"0"`
+}
+
+func NewParseJSONFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("ParseJSON", &ParseJSONArguments[K]{}, createParseJSONFunction[K])
+}
+
+func createParseJSONFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*ParseJSONArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("ParseJSONFactory args must be of type *ParseJSONArguments[K]")
+	}
+
+	return parseJSON(args.Target), nil
+}
+
+// parseJSON returns a `pcommon.Map` struct that is a result of parsing the target string as JSON
 // Each JSON type is converted into a `pdata.Value` using the following map:
 //
 //	JSON boolean -> bool
@@ -32,7 +51,7 @@ import (
 //	JSON null    -> nil
 //	JSON arrays  -> pdata.SliceValue
 //	JSON objects -> map[string]any
-func ParseJSON[K any](target ottl.StringGetter[K]) (ottl.ExprFunc[K], error) {
+func parseJSON[K any](target ottl.StringGetter[K]) ottl.ExprFunc[K] {
 	return func(ctx context.Context, tCtx K) (interface{}, error) {
 		targetVal, err := target.Get(ctx, tCtx)
 		if err != nil {
@@ -46,5 +65,5 @@ func ParseJSON[K any](target ottl.StringGetter[K]) (ottl.ExprFunc[K], error) {
 		result := pcommon.NewMap()
 		err = result.FromRaw(parsedValue)
 		return result, err
-	}, nil
+	}
 }
diff --git a/pkg/ottl/ottlfuncs/func_parse_json_test.go b/pkg/ottl/ottlfuncs/func_parse_json_test.go
index e64cc32df2b7..bde237ac52a7 100644
--- a/pkg/ottl/ottlfuncs/func_parse_json_test.go
+++ b/pkg/ottl/ottlfuncs/func_parse_json_test.go
@@ -148,9 +148,7 @@ func Test_ParseJSON(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			exprFunc, err := ParseJSON(tt.target)
-			assert.NoError(t, err)
-
+			exprFunc := parseJSON(tt.target)
 			result, err := exprFunc(context.Background(), nil)
 			assert.NoError(t, err)
 
@@ -177,8 +175,7 @@ func Test_ParseJSON_Error(t *testing.T) {
 			return 1, nil
 		},
 	}
-	exprFunc, err := ParseJSON[interface{}](target)
-	assert.NoError(t, err)
-	_, err = exprFunc(context.Background(), nil)
+	exprFunc := parseJSON[interface{}](target)
+	_, err := exprFunc(context.Background(), nil)
 	assert.Error(t, err)
 }
diff --git a/pkg/ottl/ottlfuncs/func_replace_all_matches.go b/pkg/ottl/ottlfuncs/func_replace_all_matches.go
index 78535ab65cf9..6993e0360f19 100644
--- a/pkg/ottl/ottlfuncs/func_replace_all_matches.go
+++ b/pkg/ottl/ottlfuncs/func_replace_all_matches.go
@@ -24,7 +24,27 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func ReplaceAllMatches[K any](target ottl.PMapGetter[K], pattern string, replacement string) (ottl.ExprFunc[K], error) {
+type ReplaceAllMatchesArguments[K any] struct {
+	Target      ottl.PMapGetter[K] `ottlarg:"0"`
+	Pattern     string             `ottlarg:"1"`
+	Replacement string             `ottlarg:"2"`
+}
+
+func NewReplaceAllMatchesFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("replace_all_matches", &ReplaceAllMatchesArguments[K]{}, createReplaceAllMatchesFunction[K])
+}
+
+func createReplaceAllMatchesFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*ReplaceAllMatchesArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("ReplaceAllMatchesFactory args must be of type *ReplaceAllMatchesArguments[K]")
+	}
+
+	return replaceAllMatches(args.Target, args.Pattern, args.Replacement)
+}
+
+func replaceAllMatches[K any](target ottl.PMapGetter[K], pattern string, replacement string) (ottl.ExprFunc[K], error) {
 	glob, err := glob.Compile(pattern)
 	if err != nil {
 		return nil, fmt.Errorf("the pattern supplied to replace_match is not a valid pattern: %w", err)
diff --git a/pkg/ottl/ottlfuncs/func_replace_all_matches_test.go b/pkg/ottl/ottlfuncs/func_replace_all_matches_test.go
index 3e4d1ef45eb0..7dc1f31e1abd 100644
--- a/pkg/ottl/ottlfuncs/func_replace_all_matches_test.go
+++ b/pkg/ottl/ottlfuncs/func_replace_all_matches_test.go
@@ -71,7 +71,7 @@ func Test_replaceAllMatches(t *testing.T) {
 			scenarioMap := pcommon.NewMap()
 			input.CopyTo(scenarioMap)
 
-			exprFunc, err := ReplaceAllMatches(tt.target, tt.pattern, tt.replacement)
+			exprFunc, err := replaceAllMatches(tt.target, tt.pattern, tt.replacement)
 			assert.NoError(t, err)
 
 			result, err := exprFunc(nil, scenarioMap)
@@ -94,7 +94,7 @@ func Test_replaceAllMatches_bad_input(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := ReplaceAllMatches[interface{}](target, "*", "{replacement}")
+	exprFunc, err := replaceAllMatches[interface{}](target, "*", "{replacement}")
 	assert.NoError(t, err)
 	_, err = exprFunc(nil, input)
 	assert.Error(t, err)
@@ -107,7 +107,7 @@ func Test_replaceAllMatches_get_nil(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := ReplaceAllMatches[interface{}](target, "*", "{anything}")
+	exprFunc, err := replaceAllMatches[interface{}](target, "*", "{anything}")
 	assert.NoError(t, err)
 	_, err = exprFunc(nil, nil)
 	assert.Error(t, err)
diff --git a/pkg/ottl/ottlfuncs/func_replace_all_patterns.go b/pkg/ottl/ottlfuncs/func_replace_all_patterns.go
index 9f22769227a3..b722ddbdadc4 100644
--- a/pkg/ottl/ottlfuncs/func_replace_all_patterns.go
+++ b/pkg/ottl/ottlfuncs/func_replace_all_patterns.go
@@ -29,7 +29,28 @@ const (
 	modeValue = "value"
 )
 
-func ReplaceAllPatterns[K any](target ottl.PMapGetter[K], mode string, regexPattern string, replacement string) (ottl.ExprFunc[K], error) {
+type ReplaceAllPatternsArguments[K any] struct {
+	Target       ottl.PMapGetter[K] `ottlarg:"0"`
+	Mode         string             `ottlarg:"1"`
+	RegexPattern string             `ottlarg:"2"`
+	Replacement  string             `ottlarg:"3"`
+}
+
+func NewReplaceAllPatternsFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("replace_all_patterns", &ReplaceAllPatternsArguments[K]{}, createReplaceAllPatternsFunction[K])
+}
+
+func createReplaceAllPatternsFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*ReplaceAllPatternsArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("ReplaceAllPatternsFactory args must be of type *ReplaceAllPatternsArguments[K]")
+	}
+
+	return replaceAllPatterns(args.Target, args.Mode, args.RegexPattern, args.Replacement)
+}
+
+func replaceAllPatterns[K any](target ottl.PMapGetter[K], mode string, regexPattern string, replacement string) (ottl.ExprFunc[K], error) {
 	compiledPattern, err := regexp.Compile(regexPattern)
 	if err != nil {
 		return nil, fmt.Errorf("the regex pattern supplied to replace_all_patterns is not a valid pattern: %w", err)
diff --git a/pkg/ottl/ottlfuncs/func_replace_all_patterns_test.go b/pkg/ottl/ottlfuncs/func_replace_all_patterns_test.go
index 996df1a01d7a..4c3876a6da06 100644
--- a/pkg/ottl/ottlfuncs/func_replace_all_patterns_test.go
+++ b/pkg/ottl/ottlfuncs/func_replace_all_patterns_test.go
@@ -179,7 +179,7 @@ func Test_replaceAllPatterns(t *testing.T) {
 			scenarioMap := pcommon.NewMap()
 			input.CopyTo(scenarioMap)
 
-			exprFunc, err := ReplaceAllPatterns[pcommon.Map](tt.target, tt.mode, tt.pattern, tt.replacement)
+			exprFunc, err := replaceAllPatterns[pcommon.Map](tt.target, tt.mode, tt.pattern, tt.replacement)
 			assert.NoError(t, err)
 
 			_, err = exprFunc(nil, scenarioMap)
@@ -202,7 +202,7 @@ func Test_replaceAllPatterns_bad_input(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := ReplaceAllPatterns[interface{}](target, modeValue, "regexpattern", "{replacement}")
+	exprFunc, err := replaceAllPatterns[interface{}](target, modeValue, "regexpattern", "{replacement}")
 	assert.Nil(t, err)
 
 	_, err = exprFunc(nil, input)
@@ -216,7 +216,7 @@ func Test_replaceAllPatterns_get_nil(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := ReplaceAllPatterns[interface{}](target, modeValue, "regexp", "{anything}")
+	exprFunc, err := replaceAllPatterns[interface{}](target, modeValue, "regexp", "{anything}")
 	assert.NoError(t, err)
 
 	_, err = exprFunc(nil, nil)
@@ -232,7 +232,7 @@ func Test_replaceAllPatterns_invalid_pattern(t *testing.T) {
 	}
 
 	invalidRegexPattern := "*"
-	exprFunc, err := ReplaceAllPatterns[interface{}](target, modeValue, invalidRegexPattern, "{anything}")
+	exprFunc, err := replaceAllPatterns[interface{}](target, modeValue, invalidRegexPattern, "{anything}")
 	require.Error(t, err)
 	assert.ErrorContains(t, err, "error parsing regexp:")
 	assert.Nil(t, exprFunc)
@@ -247,7 +247,7 @@ func Test_replaceAllPatterns_invalid_model(t *testing.T) {
 	}
 
 	invalidMode := "invalid"
-	exprFunc, err := ReplaceAllPatterns[interface{}](target, invalidMode, "regex", "{anything}")
+	exprFunc, err := replaceAllPatterns[interface{}](target, invalidMode, "regex", "{anything}")
 	assert.Nil(t, exprFunc)
 	assert.Contains(t, err.Error(), "invalid mode")
 }
diff --git a/pkg/ottl/ottlfuncs/func_replace_match.go b/pkg/ottl/ottlfuncs/func_replace_match.go
index db5796a32456..83945cf190d5 100644
--- a/pkg/ottl/ottlfuncs/func_replace_match.go
+++ b/pkg/ottl/ottlfuncs/func_replace_match.go
@@ -23,7 +23,27 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func ReplaceMatch[K any](target ottl.GetSetter[K], pattern string, replacement string) (ottl.ExprFunc[K], error) {
+type ReplaceMatchArguments[K any] struct {
+	Target      ottl.GetSetter[K] `ottlarg:"0"`
+	Pattern     string            `ottlarg:"1"`
+	Replacement string            `ottlarg:"2"`
+}
+
+func NewReplaceMatchFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("replace_match", &ReplaceMatchArguments[K]{}, createReplaceMatchFunction[K])
+}
+
+func createReplaceMatchFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*ReplaceMatchArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("ReplaceMatchFactory args must be of type *ReplaceMatchArguments[K]")
+	}
+
+	return replaceMatch(args.Target, args.Pattern, args.Replacement)
+}
+
+func replaceMatch[K any](target ottl.GetSetter[K], pattern string, replacement string) (ottl.ExprFunc[K], error) {
 	glob, err := glob.Compile(pattern)
 	if err != nil {
 		return nil, fmt.Errorf("the pattern supplied to replace_match is not a valid pattern: %w", err)
diff --git a/pkg/ottl/ottlfuncs/func_replace_match_test.go b/pkg/ottl/ottlfuncs/func_replace_match_test.go
index a414c41f0f51..4f385b087ad0 100644
--- a/pkg/ottl/ottlfuncs/func_replace_match_test.go
+++ b/pkg/ottl/ottlfuncs/func_replace_match_test.go
@@ -67,7 +67,7 @@ func Test_replaceMatch(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			scenarioValue := pcommon.NewValueStr(input.Str())
 
-			exprFunc, err := ReplaceMatch(tt.target, tt.pattern, tt.replacement)
+			exprFunc, err := replaceMatch(tt.target, tt.pattern, tt.replacement)
 			assert.NoError(t, err)
 			result, err := exprFunc(nil, scenarioValue)
 			assert.NoError(t, err)
@@ -93,7 +93,7 @@ func Test_replaceMatch_bad_input(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := ReplaceMatch[interface{}](target, "*", "{replacement}")
+	exprFunc, err := replaceMatch[interface{}](target, "*", "{replacement}")
 	assert.NoError(t, err)
 
 	result, err := exprFunc(nil, input)
@@ -114,7 +114,7 @@ func Test_replaceMatch_get_nil(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := ReplaceMatch[interface{}](target, "*", "{anything}")
+	exprFunc, err := replaceMatch[interface{}](target, "*", "{anything}")
 	assert.NoError(t, err)
 
 	result, err := exprFunc(nil, nil)
diff --git a/pkg/ottl/ottlfuncs/func_replace_pattern.go b/pkg/ottl/ottlfuncs/func_replace_pattern.go
index 57fdb3e0b4ee..01a7a4493225 100644
--- a/pkg/ottl/ottlfuncs/func_replace_pattern.go
+++ b/pkg/ottl/ottlfuncs/func_replace_pattern.go
@@ -22,7 +22,27 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func ReplacePattern[K any](target ottl.GetSetter[K], regexPattern string, replacement string) (ottl.ExprFunc[K], error) {
+type ReplacePatternArguments[K any] struct {
+	Target       ottl.GetSetter[K] `ottlarg:"0"`
+	RegexPattern string            `ottlarg:"1"`
+	Replacement  string            `ottlarg:"2"`
+}
+
+func NewReplacePatternFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("replace_pattern", &ReplacePatternArguments[K]{}, createReplacePatternFunction[K])
+}
+
+func createReplacePatternFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*ReplacePatternArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("ReplacePatternFactory args must be of type *ReplacePatternArguments[K]")
+	}
+
+	return replacePattern(args.Target, args.RegexPattern, args.Replacement)
+}
+
+func replacePattern[K any](target ottl.GetSetter[K], regexPattern string, replacement string) (ottl.ExprFunc[K], error) {
 	compiledPattern, err := regexp.Compile(regexPattern)
 	if err != nil {
 		return nil, fmt.Errorf("the regex pattern supplied to replace_pattern is not a valid pattern: %w", err)
diff --git a/pkg/ottl/ottlfuncs/func_replace_pattern_test.go b/pkg/ottl/ottlfuncs/func_replace_pattern_test.go
index fe51fac55825..b44e77f9e905 100644
--- a/pkg/ottl/ottlfuncs/func_replace_pattern_test.go
+++ b/pkg/ottl/ottlfuncs/func_replace_pattern_test.go
@@ -95,7 +95,7 @@ func Test_replacePattern(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			scenarioValue := pcommon.NewValueStr(input.Str())
 
-			exprFunc, err := ReplacePattern(tt.target, tt.pattern, tt.replacement)
+			exprFunc, err := replacePattern(tt.target, tt.pattern, tt.replacement)
 			assert.NoError(t, err)
 
 			result, err := exprFunc(nil, scenarioValue)
@@ -122,7 +122,7 @@ func Test_replacePattern_bad_input(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := ReplacePattern[interface{}](target, "regexp", "{replacement}")
+	exprFunc, err := replacePattern[interface{}](target, "regexp", "{replacement}")
 	assert.NoError(t, err)
 
 	result, err := exprFunc(nil, input)
@@ -142,7 +142,7 @@ func Test_replacePattern_get_nil(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := ReplacePattern[interface{}](target, `nomatch\=[^\s]*(\s?)`, "{anything}")
+	exprFunc, err := replacePattern[interface{}](target, `nomatch\=[^\s]*(\s?)`, "{anything}")
 	assert.NoError(t, err)
 
 	result, err := exprFunc(nil, nil)
@@ -163,7 +163,7 @@ func Test_replacePatterns_invalid_pattern(t *testing.T) {
 	}
 
 	invalidRegexPattern := "*"
-	_, err := ReplacePattern[interface{}](target, invalidRegexPattern, "{anything}")
+	_, err := replacePattern[interface{}](target, invalidRegexPattern, "{anything}")
 	require.Error(t, err)
 	assert.ErrorContains(t, err, "error parsing regexp:")
 }
diff --git a/pkg/ottl/ottlfuncs/func_set.go b/pkg/ottl/ottlfuncs/func_set.go
index 617cd39383c8..a043d6d1d6b3 100644
--- a/pkg/ottl/ottlfuncs/func_set.go
+++ b/pkg/ottl/ottlfuncs/func_set.go
@@ -16,11 +16,31 @@ package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-c
 
 import (
 	"context"
+	"fmt"
 
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func Set[K any](target ottl.Setter[K], value ottl.Getter[K]) (ottl.ExprFunc[K], error) {
+type SetArguments[K any] struct {
+	Target ottl.Setter[K] `ottlarg:"0"`
+	Value  ottl.Getter[K] `ottlarg:"1"`
+}
+
+func NewSetFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("set", &SetArguments[K]{}, createSetFunction[K])
+}
+
+func createSetFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*SetArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("SetFactory args must be of type *SetArguments[K]")
+	}
+
+	return set(args.Target, args.Value), nil
+}
+
+func set[K any](target ottl.Setter[K], value ottl.Getter[K]) ottl.ExprFunc[K] {
 	return func(ctx context.Context, tCtx K) (interface{}, error) {
 		val, err := value.Get(ctx, tCtx)
 		if err != nil {
@@ -35,5 +55,5 @@ func Set[K any](target ottl.Setter[K], value ottl.Getter[K]) (ottl.ExprFunc[K],
 			}
 		}
 		return nil, nil
-	}, nil
+	}
 }
diff --git a/pkg/ottl/ottlfuncs/func_set_test.go b/pkg/ottl/ottlfuncs/func_set_test.go
index 8751957a4e4b..1228e668869d 100644
--- a/pkg/ottl/ottlfuncs/func_set_test.go
+++ b/pkg/ottl/ottlfuncs/func_set_test.go
@@ -69,8 +69,7 @@ func Test_set(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			scenarioValue := pcommon.NewValueStr(input.Str())
 
-			exprFunc, err := Set(tt.setter, tt.getter)
-			assert.NoError(t, err)
+			exprFunc := set(tt.setter, tt.getter)
 
 			result, err := exprFunc(nil, scenarioValue)
 			assert.NoError(t, err)
@@ -98,8 +97,7 @@ func Test_set_get_nil(t *testing.T) {
 		},
 	}
 
-	exprFunc, err := Set[interface{}](setter, getter)
-	assert.NoError(t, err)
+	exprFunc := set[interface{}](setter, getter)
 
 	result, err := exprFunc(nil, nil)
 	assert.NoError(t, err)
diff --git a/pkg/ottl/ottlfuncs/func_span_id.go b/pkg/ottl/ottlfuncs/func_span_id.go
index 1ec1febe88bd..76e15a4eb98a 100644
--- a/pkg/ottl/ottlfuncs/func_span_id.go
+++ b/pkg/ottl/ottlfuncs/func_span_id.go
@@ -17,13 +17,32 @@ package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-c
 import (
 	"context"
 	"errors"
+	"fmt"
 
 	"go.opentelemetry.io/collector/pdata/pcommon"
 
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func SpanID[K any](bytes []byte) (ottl.ExprFunc[K], error) {
+type SpanIDArguments[K any] struct {
+	Bytes []byte `ottlarg:"0"`
+}
+
+func NewSpanIDFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("SpanID", &SpanIDArguments[K]{}, createSpanIDFunction[K])
+}
+
+func createSpanIDFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*SpanIDArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("SpanIDFactory args must be of type *SpanIDArguments[K]")
+	}
+
+	return spanID[K](args.Bytes)
+}
+
+func spanID[K any](bytes []byte) (ottl.ExprFunc[K], error) {
 	if len(bytes) != 8 {
 		return nil, errors.New("span ids must be 8 bytes")
 	}
diff --git a/pkg/ottl/ottlfuncs/func_span_id_test.go b/pkg/ottl/ottlfuncs/func_span_id_test.go
index c1532990418e..a41bfb82c549 100644
--- a/pkg/ottl/ottlfuncs/func_span_id_test.go
+++ b/pkg/ottl/ottlfuncs/func_span_id_test.go
@@ -36,7 +36,7 @@ func Test_spanID(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			exprFunc, err := SpanID[interface{}](tt.bytes)
+			exprFunc, err := spanID[interface{}](tt.bytes)
 			assert.NoError(t, err)
 			result, err := exprFunc(nil, nil)
 			assert.NoError(t, err)
@@ -61,7 +61,7 @@ func Test_spanID_validation(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			_, err := SpanID[interface{}](tt.bytes)
+			_, err := spanID[interface{}](tt.bytes)
 			require.Error(t, err)
 			assert.ErrorContains(t, err, "span ids must be 8 bytes")
 		})
diff --git a/pkg/ottl/ottlfuncs/func_split.go b/pkg/ottl/ottlfuncs/func_split.go
index 5f370c7354d4..55c12b115107 100644
--- a/pkg/ottl/ottlfuncs/func_split.go
+++ b/pkg/ottl/ottlfuncs/func_split.go
@@ -16,17 +16,37 @@ package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-c
 
 import (
 	"context"
+	"fmt"
 	"strings"
 
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func Split[K any](target ottl.StringGetter[K], delimiter string) (ottl.ExprFunc[K], error) {
+type SplitArguments[K any] struct {
+	Target    ottl.StringGetter[K] `ottlarg:"0"`
+	Delimiter string               `ottlarg:"1"`
+}
+
+func NewSplitFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("Split", &SplitArguments[K]{}, createSplitFunction[K])
+}
+
+func createSplitFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*SplitArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("SplitFactory args must be of type *SplitArguments[K]")
+	}
+
+	return split(args.Target, args.Delimiter), nil
+}
+
+func split[K any](target ottl.StringGetter[K], delimiter string) ottl.ExprFunc[K] {
 	return func(ctx context.Context, tCtx K) (interface{}, error) {
 		val, err := target.Get(ctx, tCtx)
 		if err != nil {
 			return nil, err
 		}
 		return strings.Split(val, delimiter), nil
-	}, nil
+	}
 }
diff --git a/pkg/ottl/ottlfuncs/func_split_test.go b/pkg/ottl/ottlfuncs/func_split_test.go
index 7ad8d3e32615..cdd5602d4edd 100644
--- a/pkg/ottl/ottlfuncs/func_split_test.go
+++ b/pkg/ottl/ottlfuncs/func_split_test.go
@@ -73,8 +73,7 @@ func Test_split(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			exprFunc, err := Split(tt.target, tt.delimiter)
-			assert.NoError(t, err)
+			exprFunc := split(tt.target, tt.delimiter)
 			result, err := exprFunc(nil, nil)
 			assert.NoError(t, err)
 			assert.Equal(t, tt.expected, result)
@@ -88,8 +87,7 @@ func Test_Split_Error(t *testing.T) {
 			return 1, nil
 		},
 	}
-	exprFunc, err := Split[interface{}](target, ",")
-	assert.NoError(t, err)
-	_, err = exprFunc(context.Background(), nil)
+	exprFunc := split[interface{}](target, ",")
+	_, err := exprFunc(context.Background(), nil)
 	assert.Error(t, err)
 }
diff --git a/pkg/ottl/ottlfuncs/func_substring.go b/pkg/ottl/ottlfuncs/func_substring.go
index 10cdee594124..379aaf889507 100644
--- a/pkg/ottl/ottlfuncs/func_substring.go
+++ b/pkg/ottl/ottlfuncs/func_substring.go
@@ -21,7 +21,27 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func Substring[K any](target ottl.StringGetter[K], start int64, length int64) (ottl.ExprFunc[K], error) {
+type SubstringArguments[K any] struct {
+	Target ottl.StringGetter[K] `ottlarg:"0"`
+	Start  int64                `ottlarg:"1"`
+	Length int64                `ottlarg:"2"`
+}
+
+func NewSubstringFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("Substring", &SubstringArguments[K]{}, createSubstringFunction[K])
+}
+
+func createSubstringFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*SubstringArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("SubstringFactory args must be of type *SubstringArguments[K]")
+	}
+
+	return substring(args.Target, args.Start, args.Length)
+}
+
+func substring[K any](target ottl.StringGetter[K], start int64, length int64) (ottl.ExprFunc[K], error) {
 	if start < 0 {
 		return nil, fmt.Errorf("invalid start for substring function, %d cannot be negative", start)
 	}
diff --git a/pkg/ottl/ottlfuncs/func_substring_test.go b/pkg/ottl/ottlfuncs/func_substring_test.go
index 389479709d71..e98a5df1fe0a 100644
--- a/pkg/ottl/ottlfuncs/func_substring_test.go
+++ b/pkg/ottl/ottlfuncs/func_substring_test.go
@@ -56,7 +56,7 @@ func Test_substring(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			exprFunc, err := Substring(tt.target, tt.start, tt.length)
+			exprFunc, err := substring(tt.target, tt.start, tt.length)
 			assert.NoError(t, err)
 			result, err := exprFunc(nil, nil)
 			assert.NoError(t, err)
@@ -95,7 +95,7 @@ func Test_substring_validation(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			_, err := Substring(tt.target, tt.start, tt.length)
+			_, err := substring(tt.target, tt.start, tt.length)
 			assert.Error(t, err)
 		})
 	}
@@ -151,7 +151,7 @@ func Test_substring_error(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			exprFunc, err := Substring(tt.target, tt.start, tt.length)
+			exprFunc, err := substring(tt.target, tt.start, tt.length)
 			assert.NoError(t, err)
 			result, err := exprFunc(nil, nil)
 			assert.Error(t, err)
diff --git a/pkg/ottl/ottlfuncs/func_trace_id.go b/pkg/ottl/ottlfuncs/func_trace_id.go
index e09438a620aa..0833204e02d0 100644
--- a/pkg/ottl/ottlfuncs/func_trace_id.go
+++ b/pkg/ottl/ottlfuncs/func_trace_id.go
@@ -17,13 +17,32 @@ package ottlfuncs // import "github.com/open-telemetry/opentelemetry-collector-c
 import (
 	"context"
 	"errors"
+	"fmt"
 
 	"go.opentelemetry.io/collector/pdata/pcommon"
 
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
-func TraceID[K any](bytes []byte) (ottl.ExprFunc[K], error) {
+type TraceIDArguments[K any] struct {
+	Bytes []byte `ottlarg:"0"`
+}
+
+func NewTraceIDFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("TraceID", &TraceIDArguments[K]{}, createTraceIDFunction[K])
+}
+
+func createTraceIDFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*TraceIDArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("TraceIDFactory args must be of type *TraceIDArguments[K]")
+	}
+
+	return traceID[K](args.Bytes)
+}
+
+func traceID[K any](bytes []byte) (ottl.ExprFunc[K], error) {
 	if len(bytes) != 16 {
 		return nil, errors.New("traces ids must be 16 bytes")
 	}
diff --git a/pkg/ottl/ottlfuncs/func_trace_id_test.go b/pkg/ottl/ottlfuncs/func_trace_id_test.go
index 0ad485dab190..69a50151dd19 100644
--- a/pkg/ottl/ottlfuncs/func_trace_id_test.go
+++ b/pkg/ottl/ottlfuncs/func_trace_id_test.go
@@ -36,7 +36,7 @@ func Test_traceID(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			exprFunc, err := TraceID[interface{}](tt.bytes)
+			exprFunc, err := traceID[interface{}](tt.bytes)
 			assert.NoError(t, err)
 			result, err := exprFunc(nil, nil)
 			assert.NoError(t, err)
@@ -61,7 +61,7 @@ func Test_traceID_validation(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			_, err := TraceID[interface{}](tt.bytes)
+			_, err := traceID[interface{}](tt.bytes)
 			require.Error(t, err)
 			assert.ErrorContains(t, err, "traces ids must be 16 bytes")
 		})
diff --git a/pkg/ottl/ottlfuncs/func_truncate_all.go b/pkg/ottl/ottlfuncs/func_truncate_all.go
index 894c256b44f4..7a95609d5748 100644
--- a/pkg/ottl/ottlfuncs/func_truncate_all.go
+++ b/pkg/ottl/ottlfuncs/func_truncate_all.go
@@ -23,6 +23,25 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 )
 
+type TruncateAllArguments[K any] struct {
+	Target ottl.PMapGetter[K] `ottlarg:"0"`
+	Limit  int64              `ottlarg:"1"`
+}
+
+func NewTruncateAllFactory[K any]() ottl.Factory[K] {
+	return ottl.NewFactory("truncate_all", &TruncateAllArguments[K]{}, createTruncateAllFunction[K])
+}
+
+func createTruncateAllFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[K], error) {
+	args, ok := oArgs.(*TruncateAllArguments[K])
+
+	if !ok {
+		return nil, fmt.Errorf("TruncateAllFactory args must be of type *TruncateAllArguments[K]")
+	}
+
+	return TruncateAll(args.Target, args.Limit)
+}
+
 func TruncateAll[K any](target ottl.PMapGetter[K], limit int64) (ottl.ExprFunc[K], error) {
 	if limit < 0 {
 		return nil, fmt.Errorf("invalid limit for truncate_all function, %d cannot be negative", limit)
diff --git a/pkg/ottl/parser.go b/pkg/ottl/parser.go
index afc98dc9d4b7..54bf827bb74f 100644
--- a/pkg/ottl/parser.go
+++ b/pkg/ottl/parser.go
@@ -43,7 +43,7 @@ func (e *ErrorMode) UnmarshalText(text []byte) error {
 }
 
 type Parser[K any] struct {
-	functions         map[string]interface{}
+	functions         map[string]Factory[K]
 	pathParser        PathExpressionParser[K]
 	enumParser        EnumParser
 	telemetrySettings component.TelemetrySettings
@@ -77,7 +77,7 @@ func (s *Statement[K]) Execute(ctx context.Context, tCtx K) (any, bool, error) {
 }
 
 func NewParser[K any](
-	functions map[string]interface{},
+	functions map[string]Factory[K],
 	pathParser PathExpressionParser[K],
 	settings component.TelemetrySettings,
 	options ...Option[K],
diff --git a/processor/filterprocessor/internal/common/functions.go b/processor/filterprocessor/internal/common/functions.go
index ce8d56b96a6d..23c8af9b3516 100644
--- a/processor/filterprocessor/internal/common/functions.go
+++ b/processor/filterprocessor/internal/common/functions.go
@@ -25,19 +25,59 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlmetric"
 )
 
-func MetricFunctions() map[string]interface{} {
+func MetricFunctions() map[string]ottl.Factory[ottlmetric.TransformContext] {
 	funcs := filterottl.StandardMetricFuncs()
-	funcs["HasAttrKeyOnDatapoint"] = hasAttributeKeyOnDatapoint
-	funcs["HasAttrOnDatapoint"] = hasAttributeOnDatapoint
+	hasAttributeKeyOnDatapoint := newHasAttributeKeyOnDatapointFactory()
+	funcs[hasAttributeKeyOnDatapoint.Name()] = hasAttributeKeyOnDatapoint
+
+	hasAttributeOnDatapoint := newHasAttributeOnDatapointFactory()
+	funcs[hasAttributeOnDatapoint.Name()] = hasAttributeOnDatapoint
 	return funcs
 }
 
+type hasAttributeOnDatapointArguments struct {
+	Key         string `ottlarg:"0"`
+	ExpectedVal string `ottlarg:"1"`
+}
+
+func newHasAttributeOnDatapointFactory() ottl.Factory[ottlmetric.TransformContext] {
+	return ottl.NewFactory("HasAttrOnDatapoint", &hasAttributeOnDatapointArguments{}, createHasAttributeOnDatapointFunction)
+}
+
+func createHasAttributeOnDatapointFunction(fCtx ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[ottlmetric.TransformContext], error) {
+	args, ok := oArgs.(*hasAttributeOnDatapointArguments)
+
+	if !ok {
+		return nil, fmt.Errorf("hasAttributeOnDatapointFactory args must be of type *hasAttributeOnDatapointArguments")
+	}
+
+	return hasAttributeOnDatapoint(args.Key, args.ExpectedVal)
+}
+
 func hasAttributeOnDatapoint(key string, expectedVal string) (ottl.ExprFunc[ottlmetric.TransformContext], error) {
 	return func(ctx context.Context, tCtx ottlmetric.TransformContext) (interface{}, error) {
 		return checkDataPoints(tCtx, key, &expectedVal)
 	}, nil
 }
 
+type hasAttributeKeyOnDatapointArguments struct {
+	Key string `ottlarg:"0"`
+}
+
+func newHasAttributeKeyOnDatapointFactory() ottl.Factory[ottlmetric.TransformContext] {
+	return ottl.NewFactory("HasAttrKeyOnDatapoint", &hasAttributeKeyOnDatapointArguments{}, createHasAttributeKeyOnDatapointFunction)
+}
+
+func createHasAttributeKeyOnDatapointFunction(fCtx ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[ottlmetric.TransformContext], error) {
+	args, ok := oArgs.(*hasAttributeOnDatapointArguments)
+
+	if !ok {
+		return nil, fmt.Errorf("hasAttributeKeyOnDatapointFactory args must be of type *hasAttributeOnDatapointArguments")
+	}
+
+	return hasAttributeKeyOnDatapoint(args.Key)
+}
+
 func hasAttributeKeyOnDatapoint(key string) (ottl.ExprFunc[ottlmetric.TransformContext], error) {
 	return func(ctx context.Context, tCtx ottlmetric.TransformContext) (interface{}, error) {
 		return checkDataPoints(tCtx, key, nil)
diff --git a/processor/routingprocessor/internal/common/functions.go b/processor/routingprocessor/internal/common/functions.go
index b948caf5ad03..31c058662812 100644
--- a/processor/routingprocessor/internal/common/functions.go
+++ b/processor/routingprocessor/internal/common/functions.go
@@ -21,17 +21,19 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs"
 )
 
-func Functions[K any]() map[string]interface{} {
-	return map[string]interface{}{
-		"IsMatch":              ottlfuncs.IsMatch[K],
-		"delete_key":           ottlfuncs.DeleteKey[K],
-		"delete_matching_keys": ottlfuncs.DeleteMatchingKeys[K],
+func createRouteFunction[K any](_ ottl.FunctionContext, _ ottl.Arguments) (ottl.ExprFunc[K], error) {
+	return func(context.Context, K) (interface{}, error) {
+		return true, nil
+	}, nil
+}
+
+func Functions[K any]() map[string]ottl.Factory[K] {
+	return ottl.CreateFactoryMap(
+		ottlfuncs.NewIsMatchFactory[K](),
+		ottlfuncs.NewDeleteKeyFactory[K](),
+		ottlfuncs.NewDeleteMatchingKeysFactory[K](),
 		// noop function, it is required since the parsing of conditions is not implemented yet,
-		// see https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/13545
-		"route": func() (ottl.ExprFunc[K], error) {
-			return func(context.Context, K) (interface{}, error) {
-				return true, nil
-			}, nil
-		},
-	}
+		////github.com/open-telemetry/opentelemetry-collector-contrib/issues/13545
+		ottl.NewFactory("route", nil, createRouteFunction[K]),
+	)
 }
diff --git a/processor/transformprocessor/internal/common/functions.go b/processor/transformprocessor/internal/common/functions.go
index 9bc22cbd0174..159803f5c319 100644
--- a/processor/transformprocessor/internal/common/functions.go
+++ b/processor/transformprocessor/internal/common/functions.go
@@ -15,40 +15,41 @@
 package common // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor/internal/common"
 
 import (
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlresource"
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlscope"
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/ottlfuncs"
 )
 
-func Functions[K any]() map[string]interface{} {
-	return map[string]interface{}{
-		"TraceID":              ottlfuncs.TraceID[K],
-		"SpanID":               ottlfuncs.SpanID[K],
-		"IsMatch":              ottlfuncs.IsMatch[K],
-		"Concat":               ottlfuncs.Concat[K],
-		"Split":                ottlfuncs.Split[K],
-		"Int":                  ottlfuncs.Int[K],
-		"ConvertCase":          ottlfuncs.ConvertCase[K],
-		"ParseJSON":            ottlfuncs.ParseJSON[K],
-		"Substring":            ottlfuncs.Substring[K],
-		"keep_keys":            ottlfuncs.KeepKeys[K],
-		"set":                  ottlfuncs.Set[K],
-		"truncate_all":         ottlfuncs.TruncateAll[K],
-		"limit":                ottlfuncs.Limit[K],
-		"replace_match":        ottlfuncs.ReplaceMatch[K],
-		"replace_all_matches":  ottlfuncs.ReplaceAllMatches[K],
-		"replace_pattern":      ottlfuncs.ReplacePattern[K],
-		"replace_all_patterns": ottlfuncs.ReplaceAllPatterns[K],
-		"delete_key":           ottlfuncs.DeleteKey[K],
-		"delete_matching_keys": ottlfuncs.DeleteMatchingKeys[K],
-		"merge_maps":           ottlfuncs.MergeMaps[K],
-	}
+func Functions[K any]() map[string]ottl.Factory[K] {
+	return ottl.CreateFactoryMap(
+		ottlfuncs.NewTraceIDFactory[K](),
+		ottlfuncs.NewSpanIDFactory[K](),
+		ottlfuncs.NewIsMatchFactory[K](),
+		ottlfuncs.NewConcatFactory[K](),
+		ottlfuncs.NewSplitFactory[K](),
+		ottlfuncs.NewIntFactory[K](),
+		ottlfuncs.NewConvertCaseFactory[K](),
+		ottlfuncs.NewParseJSONFactory[K](),
+		ottlfuncs.NewSubstringFactory[K](),
+		ottlfuncs.NewKeepKeysFactory[K](),
+		ottlfuncs.NewSetFactory[K](),
+		ottlfuncs.NewTruncateAllFactory[K](),
+		ottlfuncs.NewLimitFactory[K](),
+		ottlfuncs.NewReplaceMatchFactory[K](),
+		ottlfuncs.NewReplaceAllMatchesFactory[K](),
+		ottlfuncs.NewReplacePatternFactory[K](),
+		ottlfuncs.NewReplaceAllPatternsFactory[K](),
+		ottlfuncs.NewDeleteKeyFactory[K](),
+		ottlfuncs.NewDeleteMatchingKeysFactory[K](),
+		ottlfuncs.NewMergeMapsFactory[K](),
+	)
 }
 
-func ResourceFunctions() map[string]interface{} {
+func ResourceFunctions() map[string]ottl.Factory[ottlresource.TransformContext] {
 	return Functions[ottlresource.TransformContext]()
 }
 
-func ScopeFunctions() map[string]interface{} {
+func ScopeFunctions() map[string]ottl.Factory[ottlscope.TransformContext] {
 	return Functions[ottlscope.TransformContext]()
 }
diff --git a/processor/transformprocessor/internal/common/logs.go b/processor/transformprocessor/internal/common/logs.go
index 2b9ab45dfd9e..d0bd7a550a10 100644
--- a/processor/transformprocessor/internal/common/logs.go
+++ b/processor/transformprocessor/internal/common/logs.go
@@ -64,7 +64,7 @@ type LogParserCollection struct {
 
 type LogParserCollectionOption func(*LogParserCollection) error
 
-func WithLogParser(functions map[string]interface{}) LogParserCollectionOption {
+func WithLogParser(functions map[string]ottl.Factory[ottllog.TransformContext]) LogParserCollectionOption {
 	return func(lp *LogParserCollection) error {
 		logParser, err := ottllog.NewParser(functions, lp.settings)
 		if err != nil {
diff --git a/processor/transformprocessor/internal/common/metrics.go b/processor/transformprocessor/internal/common/metrics.go
index 4d27e9c6f2b9..0785dfbc50b0 100644
--- a/processor/transformprocessor/internal/common/metrics.go
+++ b/processor/transformprocessor/internal/common/metrics.go
@@ -153,7 +153,7 @@ type MetricParserCollection struct {
 
 type MetricParserCollectionOption func(*MetricParserCollection) error
 
-func WithMetricParser(functions map[string]interface{}) MetricParserCollectionOption {
+func WithMetricParser(functions map[string]ottl.Factory[ottlmetric.TransformContext]) MetricParserCollectionOption {
 	return func(mp *MetricParserCollection) error {
 		metricParser, err := ottlmetric.NewParser(functions, mp.settings)
 		if err != nil {
@@ -164,7 +164,7 @@ func WithMetricParser(functions map[string]interface{}) MetricParserCollectionOp
 	}
 }
 
-func WithDataPointParser(functions map[string]interface{}) MetricParserCollectionOption {
+func WithDataPointParser(functions map[string]ottl.Factory[ottldatapoint.TransformContext]) MetricParserCollectionOption {
 	return func(mp *MetricParserCollection) error {
 		dataPointParser, err := ottldatapoint.NewParser(functions, mp.settings)
 		if err != nil {
diff --git a/processor/transformprocessor/internal/common/traces.go b/processor/transformprocessor/internal/common/traces.go
index 73a7f03b685c..59d097525c58 100644
--- a/processor/transformprocessor/internal/common/traces.go
+++ b/processor/transformprocessor/internal/common/traces.go
@@ -100,7 +100,7 @@ type TraceParserCollection struct {
 
 type TraceParserCollectionOption func(*TraceParserCollection) error
 
-func WithSpanParser(functions map[string]interface{}) TraceParserCollectionOption {
+func WithSpanParser(functions map[string]ottl.Factory[ottlspan.TransformContext]) TraceParserCollectionOption {
 	return func(tp *TraceParserCollection) error {
 		spanParser, err := ottlspan.NewParser(functions, tp.settings)
 		if err != nil {
@@ -111,7 +111,7 @@ func WithSpanParser(functions map[string]interface{}) TraceParserCollectionOptio
 	}
 }
 
-func WithSpanEventParser(functions map[string]interface{}) TraceParserCollectionOption {
+func WithSpanEventParser(functions map[string]ottl.Factory[ottlspanevent.TransformContext]) TraceParserCollectionOption {
 	return func(tp *TraceParserCollection) error {
 		spanEventParser, err := ottlspanevent.NewParser(functions, tp.settings)
 		if err != nil {
diff --git a/processor/transformprocessor/internal/logs/functions.go b/processor/transformprocessor/internal/logs/functions.go
index 6378c293b3d9..def558789bdd 100644
--- a/processor/transformprocessor/internal/logs/functions.go
+++ b/processor/transformprocessor/internal/logs/functions.go
@@ -15,11 +15,12 @@
 package logs // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor/internal/logs"
 
 import (
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottllog"
 	"github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor/internal/common"
 )
 
-func LogFunctions() map[string]interface{} {
+func LogFunctions() map[string]ottl.Factory[ottllog.TransformContext] {
 	// No logs-only functions yet.
 	return common.Functions[ottllog.TransformContext]()
 }
diff --git a/processor/transformprocessor/internal/metrics/func_convert_gauge_to_sum.go b/processor/transformprocessor/internal/metrics/func_convert_gauge_to_sum.go
index cca5bb4928f8..7c511ae2eb5e 100644
--- a/processor/transformprocessor/internal/metrics/func_convert_gauge_to_sum.go
+++ b/processor/transformprocessor/internal/metrics/func_convert_gauge_to_sum.go
@@ -24,6 +24,25 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottldatapoint"
 )
 
+type convertGaugeToSumArguments struct {
+	StringAggTemp string `ottlarg:"0"`
+	Monotonic     bool   `ottlarg:"1"`
+}
+
+func newConvertGaugeToSumFactory() ottl.Factory[ottldatapoint.TransformContext] {
+	return ottl.NewFactory("convert_gauge_to_sum", &convertGaugeToSumArguments{}, createConvertGaugeToSumFunction)
+}
+
+func createConvertGaugeToSumFunction(fCtx ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[ottldatapoint.TransformContext], error) {
+	args, ok := oArgs.(*convertGaugeToSumArguments)
+
+	if !ok {
+		return nil, fmt.Errorf("ConvertGaugeToSumFactory args must be of type *ConvertGaugeToSumArguments")
+	}
+
+	return convertGaugeToSum(args.StringAggTemp, args.Monotonic)
+}
+
 func convertGaugeToSum(stringAggTemp string, monotonic bool) (ottl.ExprFunc[ottldatapoint.TransformContext], error) {
 	var aggTemp pmetric.AggregationTemporality
 	switch stringAggTemp {
diff --git a/processor/transformprocessor/internal/metrics/func_convert_sum_to_gauge.go b/processor/transformprocessor/internal/metrics/func_convert_sum_to_gauge.go
index aad2b38ef38d..9972df608294 100644
--- a/processor/transformprocessor/internal/metrics/func_convert_sum_to_gauge.go
+++ b/processor/transformprocessor/internal/metrics/func_convert_sum_to_gauge.go
@@ -23,6 +23,14 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottldatapoint"
 )
 
+func newConvertSumToGaugeFactory() ottl.Factory[ottldatapoint.TransformContext] {
+	return ottl.NewFactory("convert_sum_to_gauge", nil, createConvertSumToGaugeFunction)
+}
+
+func createConvertSumToGaugeFunction(fCtx ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[ottldatapoint.TransformContext], error) {
+	return convertSumToGauge()
+}
+
 func convertSumToGauge() (ottl.ExprFunc[ottldatapoint.TransformContext], error) {
 	return func(_ context.Context, tCtx ottldatapoint.TransformContext) (interface{}, error) {
 		metric := tCtx.GetMetric()
diff --git a/processor/transformprocessor/internal/metrics/func_convert_summary_count_val_to_sum.go b/processor/transformprocessor/internal/metrics/func_convert_summary_count_val_to_sum.go
index 8b6240018e61..4319a9bb7e96 100644
--- a/processor/transformprocessor/internal/metrics/func_convert_summary_count_val_to_sum.go
+++ b/processor/transformprocessor/internal/metrics/func_convert_summary_count_val_to_sum.go
@@ -24,6 +24,25 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottldatapoint"
 )
 
+type convertSummaryCountValToSumArguments struct {
+	StringAggTemp string `ottlarg:"0"`
+	Monotonic     bool   `ottlarg:"1"`
+}
+
+func newConvertSummaryCountValToSumFactory() ottl.Factory[ottldatapoint.TransformContext] {
+	return ottl.NewFactory("convert_summary_count_val_to_sum", &convertSummaryCountValToSumArguments{}, createConvertSummaryCountValToSumFunction)
+}
+
+func createConvertSummaryCountValToSumFunction(fCtx ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[ottldatapoint.TransformContext], error) {
+	args, ok := oArgs.(*convertSummaryCountValToSumArguments)
+
+	if !ok {
+		return nil, fmt.Errorf("convertSummaryCountValToSumFactory args must be of type *convertSummaryCountValToSumArguments")
+	}
+
+	return convertSummaryCountValToSum(args.StringAggTemp, args.Monotonic)
+}
+
 func convertSummaryCountValToSum(stringAggTemp string, monotonic bool) (ottl.ExprFunc[ottldatapoint.TransformContext], error) {
 	var aggTemp pmetric.AggregationTemporality
 	switch stringAggTemp {
diff --git a/processor/transformprocessor/internal/metrics/func_convert_summary_sum_val_to_sum.go b/processor/transformprocessor/internal/metrics/func_convert_summary_sum_val_to_sum.go
index 71b7bb824cbe..59b2fa4b120c 100644
--- a/processor/transformprocessor/internal/metrics/func_convert_summary_sum_val_to_sum.go
+++ b/processor/transformprocessor/internal/metrics/func_convert_summary_sum_val_to_sum.go
@@ -24,6 +24,25 @@ import (
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottldatapoint"
 )
 
+type convertSummarySumValToSumArguments struct {
+	StringAggTemp string `ottlarg:"0"`
+	Monotonic     bool   `ottlarg:"1"`
+}
+
+func newConvertSummarySumValToSumFactory() ottl.Factory[ottldatapoint.TransformContext] {
+	return ottl.NewFactory("convert_summary_sum_val_to_sum", &convertSummarySumValToSumArguments{}, createConvertSummarySumValToSumFunction)
+}
+
+func createConvertSummarySumValToSumFunction(fCtx ottl.FunctionContext, oArgs ottl.Arguments) (ottl.ExprFunc[ottldatapoint.TransformContext], error) {
+	args, ok := oArgs.(*convertSummarySumValToSumArguments)
+
+	if !ok {
+		return nil, fmt.Errorf("convertSummarySumValToSumFactory args must be of type *convertSummarySumValToSumArguments")
+	}
+
+	return convertSummarySumValToSum(args.StringAggTemp, args.Monotonic)
+}
+
 func convertSummarySumValToSum(stringAggTemp string, monotonic bool) (ottl.ExprFunc[ottldatapoint.TransformContext], error) {
 	var aggTemp pmetric.AggregationTemporality
 	switch stringAggTemp {
diff --git a/processor/transformprocessor/internal/metrics/functions.go b/processor/transformprocessor/internal/metrics/functions.go
index e9459380ef31..73afb4660151 100644
--- a/processor/transformprocessor/internal/metrics/functions.go
+++ b/processor/transformprocessor/internal/metrics/functions.go
@@ -15,30 +15,29 @@
 package metrics // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor/internal/metrics"
 
 import (
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottldatapoint"
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlmetric"
 	"github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor/internal/common"
 )
 
-// registry is a map of names to functions for metrics pipelines
-var datapointRegistry = map[string]interface{}{
-	"convert_sum_to_gauge":             convertSumToGauge,
-	"convert_gauge_to_sum":             convertGaugeToSum,
-	"convert_summary_sum_val_to_sum":   convertSummarySumValToSum,
-	"convert_summary_count_val_to_sum": convertSummaryCountValToSum,
-}
+func DataPointFunctions() map[string]ottl.Factory[ottldatapoint.TransformContext] {
+	functions := common.Functions[ottldatapoint.TransformContext]()
+
+	datapointFunctions := ottl.CreateFactoryMap[ottldatapoint.TransformContext](
+		newConvertSumToGaugeFactory(),
+		newConvertGaugeToSumFactory(),
+		newConvertSummarySumValToSumFactory(),
+		newConvertSummaryCountValToSumFactory(),
+	)
 
-func init() {
-	// Init metrics registry with default functions common to all signals
-	for k, v := range common.Functions[ottldatapoint.TransformContext]() {
-		datapointRegistry[k] = v
+	for k, v := range datapointFunctions {
+		functions[k] = v
 	}
-}
 
-func DataPointFunctions() map[string]interface{} {
-	return datapointRegistry
+	return functions
 }
 
-func MetricFunctions() map[string]interface{} {
+func MetricFunctions() map[string]ottl.Factory[ottlmetric.TransformContext] {
 	return common.Functions[ottlmetric.TransformContext]()
 }
diff --git a/processor/transformprocessor/internal/metrics/functions_test.go b/processor/transformprocessor/internal/metrics/functions_test.go
index 5ded6a8b37a5..f641c03d5b8a 100644
--- a/processor/transformprocessor/internal/metrics/functions_test.go
+++ b/processor/transformprocessor/internal/metrics/functions_test.go
@@ -27,10 +27,10 @@ import (
 
 func Test_DataPointFunctions(t *testing.T) {
 	expected := common.Functions[ottldatapoint.TransformContext]()
-	expected["convert_sum_to_gauge"] = convertSumToGauge
-	expected["convert_gauge_to_sum"] = convertGaugeToSum
-	expected["convert_summary_sum_val_to_sum"] = convertSummarySumValToSum
-	expected["convert_summary_count_val_to_sum"] = convertSummaryCountValToSum
+	expected["convert_sum_to_gauge"] = newConvertSumToGaugeFactory()
+	expected["convert_gauge_to_sum"] = newConvertGaugeToSumFactory()
+	expected["convert_summary_sum_val_to_sum"] = newConvertSummarySumValToSumFactory()
+	expected["convert_summary_count_val_to_sum"] = newConvertSummaryCountValToSumFactory()
 
 	actual := DataPointFunctions()
 
diff --git a/processor/transformprocessor/internal/traces/functions.go b/processor/transformprocessor/internal/traces/functions.go
index 31c2b9f57b3c..3157380a5608 100644
--- a/processor/transformprocessor/internal/traces/functions.go
+++ b/processor/transformprocessor/internal/traces/functions.go
@@ -15,17 +15,18 @@
 package traces // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor/internal/traces"
 
 import (
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl"
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlspan"
 	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl/contexts/ottlspanevent"
 	"github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor/internal/common"
 )
 
-func SpanFunctions() map[string]interface{} {
+func SpanFunctions() map[string]ottl.Factory[ottlspan.TransformContext] {
 	// No trace-only functions yet.
 	return common.Functions[ottlspan.TransformContext]()
 }
 
-func SpanEventFunctions() map[string]interface{} {
+func SpanEventFunctions() map[string]ottl.Factory[ottlspanevent.TransformContext] {
 	// No trace-only functions yet.
 	return common.Functions[ottlspanevent.TransformContext]()
 }