Documentation
¶
Index ¶
- Constants
- Variables
- func BuildOpenLineageRunGUID(namespace, name, jobType, runID string) string
- func BuildOpenLineageTaskGUID(namespace, name, jobType string) string
- func FormatExternalGUID(namespace, name string) string
- func InferDatasetType(namespace string) string
- func IsExternalGUID(guid string) bool
- func ValidateEventLimits(event *RunEvent) error
- type AirflowLinks
- type ColumnLineageDatasetReference
- type ColumnLineageFacet
- type ColumnLineageField
- type Dataset
- type DatasetFacets
- type DerivedRunMetadata
- type InputField
- type Job
- type OLTransform
- type Processor
- func (p *Processor) ProcessRunEvent(ctx context.Context, event *RunEvent, ...) error
- func (p *Processor) RevalidateContradictedColumnClaims(ctx context.Context, limit int) (revalidated, stillUnknown int, err error)
- func (p *Processor) RevalidateUnresolvedLineage(ctx context.Context, limit int) (revalidated, stillUnknown int, err error)
- type ResolutionStore
- type ResolvedDataset
- type Resolver
- type Run
- type RunEvent
- type SchemaFacet
- type SchemaField
- type UnmatchedNamespaceReporter
Constants ¶
const ( // MaxEventSize bounds one event rather than one request: a batch body may // be several megabytes as long as each event in it fits here. MaxEventSize = 1 << 20 // The identity caps keep the unique btree indexes of openlineage_run and // openlineage_task below PostgreSQL's index item size. A value longer than // the cap used to be stored and then fail the insert forever, so the event // never became retryable; rejecting it up front makes the failure the // producer's to fix. MaxJobNamespaceLength = 255 MaxJobNameLength = 255 MaxJobTypeLength = 64 MaxRunIDLength = 255 // Dataset names are longer than job names by nature: they can carry a // database, a schema and a table, and BigQuery prefixes a project. MaxDatasetNamespaceLength = 255 MaxDatasetNameLength = 512 // MaxEventDatasets bounds the references one event may declare, and with // them the ingestion work and stored rows one run costs. MaxEventDatasets = 1000 // MaxGUIDLength bounds the escaped GUID a run or task is indexed under. // PostgreSQL's btree item limit is about 2704 bytes, and the per-field caps // above can approach it once every character needs percent-encoding. MaxGUIDLength = 2000 // The remaining strings an event writes into the run row. The run and task // lists read them for every row of a page, so an uncapped one would let one // page read an unbounded number of bytes even though raw_payload is not // selected, and these columns are what a producer can put in a single event. MaxEventTypeLength = 64 MaxProducerLength = 512 MaxIntegrationLength = 64 MaxProcessingTypeLength = 64 MaxParentJobNamespaceLength = 255 MaxParentJobNameLength = 255 MaxParentRunIDLength = 255 MaxRootJobNamespaceLength = 255 MaxRootJobNameLength = 255 MaxRootRunIDLength = 255 // MaxColumnNameLength bounds the columnLineage strings. They reach the // indexed source_column/target_column of column_lineage, and a dataset a // facet names without listing it as an input or output builds a GUID from // its name, so both are capped like the identity fields. MaxColumnNameLength = 512 // MaxAirflowRunLogURLLength bounds the link stored on the run. It is derived // from the event with url.String(), which percent-encodes, so the stored link // can be longer than the facet it came from; past this the link is dropped // rather than stored and read back for every row of a page. MaxAirflowRunLogURLLength = 2048 )
The per-event caps. A request body limit alone leaves a single event free to be as large as the body, and every list view that later reads the run would pay for it; these keep one event, and the identity it is indexed under, small.
const ExternalDatasetGUIDPrefix = "external:"
ExternalDatasetGUIDPrefix is the prefix for external dataset GUIDs.
Variables ¶
var ErrEventTooLarge = errors.New("openlineage event exceeds the size limit")
ErrEventTooLarge reports an event beyond MaxEventSize. The ingestion handler answers it with 413 rather than the 400 a malformed event earns.
Functions ¶
func BuildOpenLineageRunGUID ¶
BuildOpenLineageRunGUID returns the stable GUID for a persisted OpenLineage run.
func BuildOpenLineageTaskGUID ¶
BuildOpenLineageTaskGUID returns the stable GUID for an aggregated OpenLineage task/job.
func FormatExternalGUID ¶
FormatExternalGUID creates an external dataset GUID.
func InferDatasetType ¶
InferDatasetType guesses the dataset type from the namespace scheme.
func IsExternalGUID ¶
IsExternalGUID returns true if the GUID belongs to an external dataset.
func ValidateEventLimits ¶
ValidateEventLimits enforces the per-event caps on a parsed event. RawJSON is set by ParseRunEvent, which is the only supported way to build one.
Types ¶
type AirflowLinks ¶
AirflowLinks contains Airflow UI URLs derived from an OpenLineage raw payload.
func AirflowLinksFromRunLogURL ¶
func AirflowLinksFromRunLogURL(runLogURL string) AirflowLinks
AirflowLinksFromRunLogURL applies the http(s) whitelist and the DAG-URL derivation to a run log URL. Ingestion stores the whitelisted link on the run row, so a reader rebuilds the same links from the column without holding the payload the facet came from.
func DeriveAirflowLinks ¶
func DeriveAirflowLinks(rawPayload []byte) AirflowLinks
DeriveAirflowLinks extracts Airflow web URLs from the original OpenLineage payload.
type ColumnLineageDatasetReference ¶
type ColumnLineageDatasetReference struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
Field string `json:"field"`
Transformations []OLTransform `json:"transformations,omitempty"`
}
ColumnLineageDatasetReference holds dataset-level lineage info.
type ColumnLineageFacet ¶
type ColumnLineageFacet struct {
Producer string `json:"_producer,omitempty"`
SchemaURL string `json:"_schemaURL,omitempty"`
Fields map[string]ColumnLineageField `json:"fields"`
Dataset []ColumnLineageDatasetReference `json:"dataset,omitempty"`
}
ColumnLineageFacet represents the OpenLineage ColumnLineageDatasetFacet.
type ColumnLineageField ¶
type ColumnLineageField struct {
InputFields []InputField `json:"inputFields"`
}
ColumnLineageField represents column-level lineage for a single output column.
type Dataset ¶
type Dataset struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
Facets DatasetFacets `json:"facets,omitempty"`
}
Dataset represents an input or output dataset in an OpenLineage event.
type DatasetFacets ¶
type DatasetFacets struct {
Schema *SchemaFacet `json:"schema,omitempty"`
ColumnLineage *ColumnLineageFacet `json:"columnLineage,omitempty"`
// Additional (non-standard) facets stored as raw JSON.
Additional map[string]json.RawMessage `json:"-"`
}
DatasetFacets holds the standard facets attached to a dataset.
type DerivedRunMetadata ¶
type DerivedRunMetadata struct {
TaskGUID string
JobType string
Integration string
ProcessingType string
ParentJobNamespace string
ParentJobName string
ParentRunID string
RootJobNamespace string
RootJobName string
RootRunID string
HasLineage bool
}
DerivedRunMetadata is the normalized OpenLineage metadata extracted from raw facets.
func DeriveRunMetadata ¶
func DeriveRunMetadata(event *RunEvent) DerivedRunMetadata
DeriveRunMetadata extracts normalized task/job information from an OpenLineage event.
type InputField ¶
type InputField struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
Field string `json:"field"`
Transformations []OLTransform `json:"transformations,omitempty"`
}
InputField identifies an input column contributing to an output column.
type Job ¶
type Job struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
Facets map[string]json.RawMessage `json:"facets,omitempty"`
}
Job represents the job entity in an OpenLineage event.
type OLTransform ¶
type OLTransform struct {
Type string `json:"type"`
Subtype string `json:"subtype"`
Description string `json:"description,omitempty"`
Masking bool `json:"masking,omitempty"`
}
OLTransform describes a transformation applied in OpenLineage.
type Processor ¶
type Processor struct {
// contains filtered or unexported fields
}
Processor handles incoming OpenLineage events and stores derived lineage.
func NewProcessor ¶
func NewProcessor(s *store.Store, lineageAnalyzer *lineage.Analyzer, reporter UnmatchedNamespaceReporter) *Processor
NewProcessor creates a new event processor. reporter is told about datasets that match no registered instance; it may be nil.
func (*Processor) ProcessRunEvent ¶
func (p *Processor) ProcessRunEvent(ctx context.Context, event *RunEvent, persistedRun *store.OpenLineageRunMessage) error
ProcessRunEvent derives lineage from a single OpenLineage RunEvent. The run is already persisted whatever its state; only a COMPLETE event yields lineage, because that is where the producer states what the run finally read and wrote.
func (*Processor) RevalidateContradictedColumnClaims ¶
func (p *Processor) RevalidateContradictedColumnClaims(ctx context.Context, limit int) (revalidated, stillUnknown int, err error)
RevalidateContradictedColumnClaims re-checks the ingested edges whose column claim the registry has come to contradict: the edge names a column on a relation that is a TABLE, and the table has no such column.
These are the edges whose relation was unknown when they were stored, so ingestion had to keep the claim unchecked. The sync that made the relation known also removed the edge from the unknown-endpoint sweep's reach, so this is the only pass that can still fix them. A claim is blanked, the edge stays as a table-level dependency, and what is still unknown around it is counted.
func (*Processor) RevalidateUnresolvedLineage ¶
func (p *Processor) RevalidateUnresolvedLineage(ctx context.Context, limit int) (revalidated, stillUnknown int, err error)
RevalidateUnresolvedLineage re-checks the edges whose endpoints the registry did not know when they were stored.
An ingested edge is kept when its relation is missing, because ingestion runs before the next schema sync and dropping it would lose the lineage of a table created minutes ago. That keeps real lineage, but it also means the edge's columns were never checked and the edge may name a relation that never appears. Once the relation does appear - or once a second look proves it is still absent - the same validation the ingestion path runs decides what the edge should say now: a column the relation does not have is blanked, and the object types are filled in. Edges whose relation is still unknown stay, and are counted so the backlog is visible instead of silent.
It returns the number of edges re-checked and the number of meta objects that still reference an unknown relation.
type ResolutionStore ¶
type ResolutionStore interface {
GetNamespaceMapping(ctx context.Context, find *store.FindNamespaceMappingMessage) (*store.NamespaceMappingMessage, error)
GetInstance(ctx context.Context, find *store.FindInstanceMessage) (*store.InstanceMessage, error)
ListInstances(ctx context.Context, find *store.FindInstanceMessage) ([]*store.InstanceMessage, error)
GetOrCreateExternalDataset(ctx context.Context, namespace, name, datasetType string) (*store.ExternalDatasetMessage, error)
}
ResolutionStore is the store surface the resolver reads: the namespace mapping, the instances behind it, and the external dataset it creates for a namespace that names no instance. It is the seam that lets the resolution rules and their per-request memoization be tested without a database.
type ResolvedDataset ¶
type ResolvedDataset struct {
GUID string
MetaType storepb.MetaType
// True if this dataset was resolved to an internal instance.
Internal bool
}
ResolvedDataset holds the result of resolving an OpenLineage dataset to an internal or external entity.
type Resolver ¶
type Resolver struct {
// contains filtered or unexported fields
}
Resolver maps OpenLineage dataset namespaces and names to internal GUIDs or external datasets.
func NewRequestScopedResolver ¶
func NewRequestScopedResolver(s ResolutionStore) *Resolver
NewRequestScopedResolver creates a Resolver that memoizes lookups for the lifetime of one request. Use NewResolver for ingestion, where a resolver may serve many resolutions and cached answers could go stale.
func NewResolver ¶
func NewResolver(s ResolutionStore, reporter UnmatchedNamespaceReporter) *Resolver
NewResolver creates a new Resolver. reporter may be nil.
func (*Resolver) ResolveDataset ¶
func (r *Resolver) ResolveDataset(ctx context.Context, namespace, datasetName string) (*ResolvedDataset, error)
ResolveDataset resolves an OpenLineage dataset (namespace + name) to a GUID and MetaType. Resolution order:
- Manual namespace_mapping table lookup
- Auto-match by parsing namespace URL and matching instance DataSource host:port
- Create/return an external dataset
func (*Resolver) ResolveDatasetPreview ¶
func (r *Resolver) ResolveDatasetPreview(ctx context.Context, namespace, datasetName string) (*ResolvedDataset, error)
ResolveDatasetPreview resolves an OpenLineage dataset without creating external-dataset rows.
type Run ¶
type Run struct {
RunID string `json:"runId"`
Facets map[string]json.RawMessage `json:"facets,omitempty"`
}
Run represents the run entity in an OpenLineage event.
type RunEvent ¶
type RunEvent struct {
EventType string `json:"eventType"`
EventTime string `json:"eventTime"`
Run Run `json:"run"`
Job Job `json:"job"`
Inputs []Dataset `json:"inputs"`
Outputs []Dataset `json:"outputs"`
Producer string `json:"producer"`
RawJSON json.RawMessage `json:"-"`
}
RunEvent represents an OpenLineage RunEvent. See: https://openlineage.io/docs/spec/run-event
func ParseRunEvent ¶
ParseRunEvent parses a raw JSON payload into a RunEvent.
type SchemaFacet ¶
type SchemaFacet struct {
Producer string `json:"_producer,omitempty"`
SchemaURL string `json:"_schemaURL,omitempty"`
Fields []SchemaField `json:"fields"`
}
SchemaFacet represents the OpenLineage SchemaDatasetFacet.
type SchemaField ¶
type SchemaField struct {
Name string `json:"name"`
Type string `json:"type"`
Description string `json:"description,omitempty"`
}
SchemaField represents a field in the schema facet.
type UnmatchedNamespaceReporter ¶
type UnmatchedNamespaceReporter interface {
ReportUnmatchedNamespace(ctx context.Context, namespace, dataset string)
}
UnmatchedNamespaceReporter is told about a dataset that matched no registered instance and was stored as an external dataset, so the lineage naming it points at something the registry does not describe. Ingestion wires the workspace notification service here; a nil reporter leaves the log as the record.