Class: OpenObserve::Dashboards

Inherits:
Resource
  • Object
show all
Includes:
DirectorySource
Defined in:
lib/openobserve/dashboards.rb

Overview

Dashboards, and the idempotent directory synchronisation deploys are built on.

Reads go through Resource#raw, and here the reason is not merely theoretical: Api::Api::Dashboards pins type: Api::Models::Dashboard, a model that is wrong twice over. OpenObserve answers these routes with a version envelope (hash, updatedAt, version, v1v8) rather than a flat dashboard, and the model declares none of it — so a real dashboard came back with no panels at all.

The request direction needs no such care: the transport passes a plain Hash through verbatim, so a v5 document reaches OpenObserve byte for byte.

Idempotence

#sync keys on the exact title, because OpenObserve assigns dashboard ids itself and ignores any dashboardId a payload carries — a file cannot claim an identity. The consequence is worth stating plainly: renaming a dashboard in the OpenObserve UI orphans it, and the next synchronisation recreates the original title alongside it. Nothing is ever deleted here, so recovering from that is a manual act.

Constant Summary collapse

DEFAULT_FOLDER =

The folder used when the caller names none. OpenObserve itself falls back to this folder on create, and update refuses to run without one, so it is pinned rather than left to the server. Deliberately not Client#folder: that one designates an alert folder, and OpenObserve scopes folders per object type.

'default'
DEFAULT_PATTERN =

Files #sync picks up. Matches the *.oo.json convention as well as plain *.json.

'*.json'

Constants inherited from Resource

Resource::AUTH

Instance Method Summary collapse

Methods included from DirectorySource

#read_definitions

Methods inherited from Resource

#initialize

Constructor Details

This class inherits a constructor from OpenObserve::Resource

Instance Method Details

#create(definition, folder: DEFAULT_FOLDER) ⇒ OpenObserve::Dashboard

Returns the created dashboard, id included.

Parameters:

  • definition (Hash)

    a dashboard document, sent verbatim

  • folder (String) (defaults to: DEFAULT_FOLDER)

Returns:



72
73
74
75
76
# File 'lib/openobserve/dashboards.rb', line 72

def create(definition, folder: DEFAULT_FOLDER)
  Dashboard.from(
    call { raw(:POST, collection_path, query: { 'folder' => folder }, body: definition) }
  )
end

#delete(id, folder: DEFAULT_FOLDER) ⇒ void

This method returns an undefined value.

Parameters:

  • id (String)

    server-assigned dashboard id

  • folder (String) (defaults to: DEFAULT_FOLDER)


96
97
98
99
# File 'lib/openobserve/dashboards.rb', line 96

def delete(id, folder: DEFAULT_FOLDER)
  call { raw(:DELETE, member_path(id), query: { 'folder' => folder }) }
  nil
end

#find_by_title(title, folder: DEFAULT_FOLDER) ⇒ OpenObserve::Dashboard?

The one dashboard whose title matches exactly, case included.

Parameters:

  • title (String)
  • folder (String) (defaults to: DEFAULT_FOLDER)

Returns:

Raises:



53
54
55
56
57
# File 'lib/openobserve/dashboards.rb', line 53

def find_by_title(title, folder: DEFAULT_FOLDER)
  exact = list(folder: folder, title: title).select { |dashboard| dashboard.title == title }

  unique(exact, title)
end

#get(id, folder: DEFAULT_FOLDER) ⇒ OpenObserve::Dashboard

Parameters:

  • id (String)

    server-assigned dashboard id

  • folder (String) (defaults to: DEFAULT_FOLDER)

Returns:

Raises:



63
64
65
66
67
# File 'lib/openobserve/dashboards.rb', line 63

def get(id, folder: DEFAULT_FOLDER)
  Dashboard.from(
    one('dashboard') { raw(:GET, member_path(id), query: { 'folder' => folder }) }
  )
end

#list(folder: DEFAULT_FOLDER, title: nil, page_size: nil) ⇒ Array<OpenObserve::Dashboard>

Parameters:

  • folder (String) (defaults to: DEFAULT_FOLDER)

    folder to list; defaults to DEFAULT_FOLDER

  • title (String, nil) (defaults to: nil)

    server-side narrowing — a case-insensitive substring match, so it reduces the page but never identifies; see #find_by_title

  • page_size (Integer, nil) (defaults to: nil)

    only honoured by OpenObserve when title is set

Returns:



39
40
41
42
43
44
45
# File 'lib/openobserve/dashboards.rb', line 39

def list(folder: DEFAULT_FOLDER, title: nil, page_size: nil)
  payload = collection do
    raw(:GET, collection_path, query: { 'folder' => folder, 'title' => title, 'pageSize' => page_size })
  end

  Array(payload && payload['dashboards']).map { |dashboard| Dashboard.from(dashboard) }
end

#sync(directory, folder: DEFAULT_FOLDER, pattern: DEFAULT_PATTERN) ⇒ Hash{Symbol=>Array<String>}

Push a directory of dashboard documents into OpenObserve, creating what is missing and overwriting what is already there. Safe to replay: a second run over an unchanged directory rewrites the same content and leaves the same set of dashboards.

Nothing is ever deleted — a dashboard the directory no longer describes stays put.

The whole folder is listed once, so the cost is one request plus one write per file, and the revision each write must echo back is taken from that listing.

Examples:

client.dashboards.sync("config/dashboards")
# => { created: ["Redis Metrics"], updated: ["Postgres Metrics"] }

Parameters:

  • directory (String)

    directory holding the documents

  • folder (String) (defaults to: DEFAULT_FOLDER)

    OpenObserve folder to synchronise into

  • pattern (String) (defaults to: DEFAULT_PATTERN)

    glob applied inside directory

Returns:

  • (Hash{Symbol=>Array<String>})

    titles, under :created and :updated

Raises:



121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/openobserve/dashboards.rb', line 121

def sync(directory, folder: DEFAULT_FOLDER, pattern: DEFAULT_PATTERN)
  definitions = read_definitions(directory, pattern, 'title', noun: 'dashboard')
  index       = index_by_title(list(folder: folder))
  result      = { created: [], updated: [] }

  definitions.each do |title, definition|
    current = unique(index[title] || [], title)
    result[current ? :updated : :created] << title
    write(current, definition, folder: folder)
  end

  result
end

#update(id, definition, revision:, folder: DEFAULT_FOLDER) ⇒ OpenObserve::Dashboard

Parameters:

  • id (String)

    server-assigned dashboard id

  • definition (Hash)

    the replacement document, sent verbatim

  • revision (String)

    the dashboard's current OpenObserve::Dashboard#revision; OpenObserve answers 500 without it and 409 when it is stale

  • folder (String) (defaults to: DEFAULT_FOLDER)

Returns:

Raises:



85
86
87
88
89
90
91
# File 'lib/openobserve/dashboards.rb', line 85

def update(id, definition, revision:, folder: DEFAULT_FOLDER)
  Dashboard.from(
    call do
      raw(:PUT, member_path(id), query: { 'folder' => folder, 'hash' => revision }, body: definition)
    end
  )
end