Skip to content

Commit db6738e

Browse files
authored
[Heartbeat] Dedupe screenshots / Extra Args (#25808)
1 parent cb085d0 commit db6738e

15 files changed

Lines changed: 329 additions & 123 deletions

File tree

CHANGELOG.next.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
106106
- Change logging in logs input to structure logging. Some log message formats have changed. {pull}25299[25299]
107107

108108
*Heartbeat*
109+
- Add support for screenshot blocks and use newer synthetics flags that only works in newer synthetics betas. {pull}25808[25808]
109110

110111
*Journalbeat*
111112

heartbeat/_meta/fields.common.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,23 @@
174174
type: text
175175
- name: stack
176176
type: text
177+
- name: screenshot_ref
178+
type: group
179+
dynamic: false
180+
fields:
181+
- name: width
182+
type: integer
183+
description: Width of the full screenshot in pixels.
184+
- name: height
185+
type: integer
186+
description: Height of the full screenshot in pixels
187+
- name: blocks
188+
type: group
189+
description: Attributes representing individual screenshot blocks. Only hash is indexed since it's the only one we'd query on.
190+
fields:
191+
- name: hash
192+
type: keyword
193+
description: Hash that uniquely identifies this image by content. Corresponds to block document id.
177194
- name: browser
178195
type: group
179196
fields:

heartbeat/docs/fields.asciidoc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10500,6 +10500,40 @@ type: text
1050010500
--
1050110501
1050210502
10503+
*`synthetics.screenshot_ref.width`*::
10504+
+
10505+
--
10506+
Width of the full screenshot in pixels.
10507+
10508+
type: integer
10509+
10510+
--
10511+
10512+
*`synthetics.screenshot_ref.height`*::
10513+
+
10514+
--
10515+
Height of the full screenshot in pixels
10516+
10517+
type: integer
10518+
10519+
--
10520+
10521+
[float]
10522+
=== blocks
10523+
10524+
Attributes representing individual screenshot blocks. Only hash is indexed since it's the only one we'd query on.
10525+
10526+
10527+
*`synthetics.screenshot_ref.blocks.hash`*::
10528+
+
10529+
--
10530+
Hash that uniquely identifies this image by content. Corresponds to block document id.
10531+
10532+
type: keyword
10533+
10534+
--
10535+
10536+
1050310537
1050410538
*`synthetics.browser.experience.name`*::
1050510539
+

heartbeat/docs/monitors/monitor-browser.asciidoc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,15 @@ Example configuration:
104104
local:
105105
path: "/path/to/synthetics/journeys"
106106
-------------------------------------------------------------------------------
107+
108+
[float]
109+
[[monitor-browser-sandbox]]
110+
==== `sandbox`
111+
112+
Set this option to `true` to enable the normally disabled chromium sandbox. Defaults to false.
113+
114+
[float]
115+
[[monitor-browser-synthetics-args]]
116+
==== `synthetics_args`
117+
118+
Extra arguments to pass to the synthetics agent package. Takes a list of strings.

heartbeat/include/fields.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/heartbeat/include/fields.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/heartbeat/monitors/browser/browser.go

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,14 @@
55
package browser
66

77
import (
8-
"context"
98
"fmt"
109
"os"
1110
"os/user"
1211
"sync"
1312

14-
"github.com/elastic/beats/v7/heartbeat/monitors/jobs"
1513
"github.com/elastic/beats/v7/heartbeat/monitors/plugin"
16-
"github.com/elastic/beats/v7/libbeat/beat"
1714
"github.com/elastic/beats/v7/libbeat/common"
1815
"github.com/elastic/beats/v7/libbeat/logp"
19-
"github.com/elastic/beats/v7/x-pack/heartbeat/monitors/browser/synthexec"
2016
)
2117

2218
func init() {
@@ -25,14 +21,14 @@ func init() {
2521

2622
var showExperimentalOnce = sync.Once{}
2723

28-
var NotSyntheticsCapableError = fmt.Errorf("synthetic monitors cannot be created outside the official elastic docker image")
24+
var ErrNotSyntheticsCapableError = fmt.Errorf("synthetic monitors cannot be created outside the official elastic docker image")
2925

3026
func create(name string, cfg *common.Config) (p plugin.Plugin, err error) {
3127
// We don't want users running synthetics in environments that don't have the required GUI libraries etc, so we check
3228
// this flag. When we're ready to support the many possible configurations of systems outside the docker environment
3329
// we can remove this check.
3430
if os.Getenv("ELASTIC_SYNTHETICS_CAPABLE") != "true" {
35-
return plugin.Plugin{}, NotSyntheticsCapableError
31+
return plugin.Plugin{}, ErrNotSyntheticsCapableError
3632
}
3733

3834
showExperimentalOnce.Do(func() {
@@ -47,36 +43,10 @@ func create(name string, cfg *common.Config) (p plugin.Plugin, err error) {
4743
return plugin.Plugin{}, fmt.Errorf("script monitors cannot be run as root! Current UID is %s", curUser.Uid)
4844
}
4945

50-
ss, err := NewSuite(cfg)
46+
s, err := NewSuite(cfg)
5147
if err != nil {
5248
return plugin.Plugin{}, err
5349
}
5450

55-
extraArgs := []string{}
56-
if ss.suiteCfg.Sandbox {
57-
extraArgs = append(extraArgs, "--sandbox")
58-
}
59-
60-
var j jobs.Job
61-
if src, ok := ss.InlineSource(); ok {
62-
j = synthexec.InlineJourneyJob(context.TODO(), src, ss.Params(), extraArgs...)
63-
} else {
64-
j = func(event *beat.Event) ([]jobs.Job, error) {
65-
err := ss.Fetch()
66-
if err != nil {
67-
return nil, fmt.Errorf("could not fetch for suite job: %w", err)
68-
}
69-
sj, err := synthexec.SuiteJob(context.TODO(), ss.Workdir(), ss.Params(), extraArgs...)
70-
if err != nil {
71-
return nil, err
72-
}
73-
return sj(event)
74-
}
75-
}
76-
77-
return plugin.Plugin{
78-
Jobs: []jobs.Job{j},
79-
Close: ss.Close,
80-
Endpoints: 1,
81-
}, nil
51+
return s.plugin(), nil
8252
}

x-pack/heartbeat/monitors/browser/config.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ type Config struct {
2525
// Name is optional for lightweight checks but required for browsers
2626
Name string `config:"name"`
2727
// Id is optional for lightweight checks but required for browsers
28-
Id string `config:"id"`
29-
Sandbox bool `config:"sandbox"`
28+
Id string `config:"id"`
29+
Sandbox bool `config:"sandbox"`
30+
SyntheticsArgs []string `config:"synthetics_args"`
3031
}
3132

3233
var ErrNameRequired = fmt.Errorf("config 'name' must be specified for this monitor")
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License;
3+
// you may not use this file except in compliance with the Elastic License.
4+
5+
package browser
6+
7+
import (
8+
"context"
9+
"fmt"
10+
11+
"github.com/elastic/beats/v7/heartbeat/monitors/jobs"
12+
"github.com/elastic/beats/v7/heartbeat/monitors/plugin"
13+
"github.com/elastic/beats/v7/libbeat/beat"
14+
"github.com/elastic/beats/v7/libbeat/common"
15+
"github.com/elastic/beats/v7/x-pack/heartbeat/monitors/browser/synthexec"
16+
)
17+
18+
type JourneyLister func(ctx context.Context, suitePath string, params common.MapStr) (journeyNames []string, err error)
19+
20+
type Suite struct {
21+
rawCfg *common.Config
22+
suiteCfg *Config
23+
}
24+
25+
func NewSuite(rawCfg *common.Config) (*Suite, error) {
26+
s := &Suite{
27+
rawCfg: rawCfg,
28+
suiteCfg: DefaultConfig(),
29+
}
30+
err := rawCfg.Unpack(s.suiteCfg)
31+
if err != nil {
32+
return nil, ErrBadConfig(err)
33+
}
34+
35+
return s, nil
36+
}
37+
38+
func ErrBadConfig(err error) error {
39+
return fmt.Errorf("could not parse suite config: %w", err)
40+
}
41+
42+
func (s *Suite) String() string {
43+
panic("implement me")
44+
}
45+
46+
func (s *Suite) Fetch() error {
47+
return s.suiteCfg.Source.Active().Fetch()
48+
}
49+
50+
func (s *Suite) Workdir() string {
51+
return s.suiteCfg.Source.Active().Workdir()
52+
}
53+
54+
func (s *Suite) InlineSource() (string, bool) {
55+
if s.suiteCfg.Source.Inline != nil {
56+
return s.suiteCfg.Source.Inline.Script, true
57+
}
58+
return "", false
59+
}
60+
61+
func (s *Suite) Params() map[string]interface{} {
62+
return s.suiteCfg.Params
63+
}
64+
65+
func (s *Suite) Close() error {
66+
if s.suiteCfg.Source.ActiveMemo != nil {
67+
s.suiteCfg.Source.ActiveMemo.Close()
68+
}
69+
70+
return nil
71+
}
72+
73+
func (s *Suite) extraArgs() []string {
74+
extraArgs := s.suiteCfg.SyntheticsArgs
75+
if s.suiteCfg.Sandbox {
76+
extraArgs = append(extraArgs, "--sandbox")
77+
}
78+
79+
return extraArgs
80+
}
81+
82+
func (s *Suite) jobs() []jobs.Job {
83+
var j jobs.Job
84+
if src, ok := s.InlineSource(); ok {
85+
j = synthexec.InlineJourneyJob(context.TODO(), src, s.Params(), s.extraArgs()...)
86+
} else {
87+
j = func(event *beat.Event) ([]jobs.Job, error) {
88+
err := s.Fetch()
89+
if err != nil {
90+
return nil, fmt.Errorf("could not fetch for suite job: %w", err)
91+
}
92+
sj, err := synthexec.SuiteJob(context.TODO(), s.Workdir(), s.Params(), s.extraArgs()...)
93+
if err != nil {
94+
return nil, err
95+
}
96+
return sj(event)
97+
}
98+
}
99+
return []jobs.Job{j}
100+
}
101+
102+
func (s *Suite) plugin() plugin.Plugin {
103+
return plugin.Plugin{
104+
Jobs: s.jobs(),
105+
Close: s.Close,
106+
Endpoints: 1,
107+
}
108+
}

x-pack/heartbeat/monitors/browser/suite_runner.go

Lines changed: 0 additions & 69 deletions
This file was deleted.

0 commit comments

Comments
 (0)