Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify creating test data for profiles support #12554

Closed
rockdaboot opened this issue Mar 3, 2025 · 3 comments · Fixed by open-telemetry/opentelemetry-collector-contrib#38430
Assignees
Labels
area:pdata pdata module related issues enhancement New feature or request

Comments

@rockdaboot
Copy link
Contributor

Component(s)

No response

Is your feature request related to a problem? Please describe.

Creating instances of pprofile.Profile for testing profiles related code is currently tedious and unnecessary hard to read. Example
Too many details of the protobuf definition are exposed and expected to be known to the writers of tests that involve profiles.

Every component that needs to create pprofile.Profile items to test with would benefit.

Describe the solution you'd like

We could use Go types for the definition of test cases without exposing protocol internals (for example, how de-duplication of items is done), and a transformation function that transforms the test case into pprofile.Profile.

Example

testcase
	tp := &testProfile{
		sampleType: []testValueType{
			{
				typ:                    "samples",
				unit:                   "count",
				aggregationTemporality: pprofile.AggregationTemporalityDelta,
			},
		},
		sample: []testSample{
			{
				timestamp: 42,
				link: testLink{
					traceID: [16]byte{0x01, 0x02},
					spanID:  [16]byte{0x03, 0x04},
				},
				value: 1,
				locations: []testLocation{
					{
						mapping: &testMapping{
							memoryStart: 0x1000,
							memoryLimit: 0x2000,
							fileOffset:  0x3000,
							fileName:    "file1",
							attributes: []testAttribute{
								{
									key:   "mapping.attribute.key",
									value: "mapping.attribute.value",
								},
							},
							hasFunctions:    true,
							hasFileNames:    true,
							hasLineNumbers:  true,
							hasInlineFrames: true,
						},
						address: 0x1000,
						line: []testLine{
							{
								line:   1,
								column: 2,
								function: testFunction{
									name:       "func1",
									systemName: "system1",
									fileName:   "file1",
									startLine:  1,
								},
							},
						},
						isFolded: true,
						attributes: []testAttribute{
							{
								key:   "location.attribute.key",
								value: "location.attribute.value",
							},
						},
					},
				},
				attributes: []testAttribute{
					{
						key:   "sample.attribute.key",
						value: "sample.attribute.value",
					},
				},
			},
		},
		timeNanos:     42,
		durationNanos: 84,
		periodType: testValueType{
			typ:  "cpu",
			unit: "nanoseconds",
		},
		period:  1e9 / 20,
		comment: []string{"comment1", "comment2"},
		defaultSampleType: testValueType{
			typ:  "samples",
			unit: "count",
		},
		profileID:              [16]byte{0x05, 0x06},
		droppedAttributesCount: 1,
		originalPayloadFormat:  "payloadFormat",
		originalPayload:        []byte{0x07, 0x08},
		attributes: []testAttribute{
			{
				key:   "profile.attribute.key",
				value: "profile.attribute.value",
			},
		},
	}

	pp, err := td.ToPProfile()

Describe alternatives you've considered

JSON definition: too error-prone, needs additional dependencies
Pre-recorded protobuf files: Requires extra amount of work, can't easily define corner-cases

Additional context

No response

@rockdaboot rockdaboot added the enhancement New feature or request label Mar 3, 2025
@atoulme atoulme transferred this issue from open-telemetry/opentelemetry-collector-contrib Mar 4, 2025
@atoulme atoulme added the area:pdata pdata module related issues label Mar 4, 2025
@rockdaboot
Copy link
Contributor Author

@atoulme Do you mind to assign the issue to me? I already have code locally.

@dmathieu
Copy link
Member

dmathieu commented Mar 5, 2025

This has been moved to collector core. However, I'm not sure that's appropriate.

The intent for these helpers it very similar to what telemetrygen does, as in generate fake data that can be used to test plugins that manipulate profiling data.
Pdata is indeed meant to manipulate profiling data, but at runtime. More advanced generation of test data for other profiles do not reside in there.

So I think this should be moved back to the contrib repository, as this is not in the pdata area.

@rockdaboot
Copy link
Contributor Author

I followed the suggestion of @dmathieu and created the PR in collector-contrib.

@atoulme Please see Damien's comment above.

atoulme pushed a commit to open-telemetry/opentelemetry-collector-contrib that referenced this issue Mar 7, 2025
)

Fixes
open-telemetry/opentelemetry-collector#12554

Currently, it is pretty tedious and error-prone to generate valid test
profiles.

This PR adds Go structs and transform functions for profiles types that
allow creating valid test cases in a human readable way. It also takes
care for some semantics that make a profile valid, for example that the
first entry in the string table is the empty string.

Here is an example from `profiles_test.go`

**Before (this produces an invalid profile, btw)**
```
	p := pprofile.NewProfiles()
	rl := p.ResourceProfiles().AppendEmpty()
	rl.Resource().Attributes().PutStr("key1", "value1")
	l := rl.ScopeProfiles().AppendEmpty().Profiles().AppendEmpty()
	attr := l.AttributeTable().AppendEmpty()
	attr.SetKey("scope-attr1")
	attr.Value().SetStr("value1")
	l.AttributeIndices().Append(0)
	l.SetProfileID(pprofile.NewProfileIDEmpty())
	rl2 := p.ResourceProfiles().AppendEmpty()
	rl2.Resource().Attributes().PutStr("key2", "value2")
	l2 := rl2.ScopeProfiles().AppendEmpty().Profiles().AppendEmpty()
	attr = l2.AttributeTable().AppendEmpty()
	attr.SetKey("scope-attr2")
	attr.Value().SetStr("value2")
	l2.AttributeIndices().Append(0)
	l2.SetProfileID(pprofile.NewProfileIDEmpty())
	return p
```

**After**
```
	p := basicProfiles()
	p.ResourceProfiles = append(p.ResourceProfiles, ResourceProfile{
		Resource: Resource{
			Attributes: []Attribute{{"key2", "value2"}},
		},
		ScopeProfiles: []ScopeProfile{
			{
				Profile: []Profile{
					{
						Attributes: []Attribute{{"scope-attr2", "value2"}},
					},
				},
			},
		},
	})
	return p.Transform()
```
where `basicProfiles()` is a helper function that creates a basic test
`Profiles`.

Planned a follow-up PR with a validator for profiles (working locally
already).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:pdata pdata module related issues enhancement New feature or request
Projects
None yet
3 participants