Commit 2d1ab599 authored by Stan Hu's avatar Stan Hu

Merge branch 'sh-geo-show-event-log-data' into 'master'

Show Geo event log and cursor data in node status page

See merge request !2681
parents 22b8a069 b01d07c8
...@@ -20,8 +20,12 @@ class GeoNodeStatus { ...@@ -20,8 +20,12 @@ class GeoNodeStatus {
this.$repositoriesFailed = $('.js-repositories-failed', this.$status); this.$repositoriesFailed = $('.js-repositories-failed', this.$status);
this.$lfsObjectsSynced = $('.js-lfs-objects-synced', this.$status); this.$lfsObjectsSynced = $('.js-lfs-objects-synced', this.$status);
this.$attachmentsSynced = $('.js-attachments-synced', this.$status); this.$attachmentsSynced = $('.js-attachments-synced', this.$status);
this.$lastEventSeen = $('.js-last-event-seen', this.$status);
this.$lastCursorEvent = $('.js-last-cursor-event', this.$status);
this.$health = $('.js-health', this.$status); this.$health = $('.js-health', this.$status);
this.endpoint = this.$el.data('status-url'); this.endpoint = this.$el.data('status-url');
this.$advancedStatus = $('.js-advanced-geo-node-status-toggler', this.$status);
this.$advancedStatus.on('click', GeoNodeStatus.toggleShowAdvancedStatus);
this.statusInterval = new gl.SmartInterval({ this.statusInterval = new gl.SmartInterval({
callback: this.getStatus.bind(this), callback: this.getStatus.bind(this),
...@@ -33,6 +37,14 @@ class GeoNodeStatus { ...@@ -33,6 +37,14 @@ class GeoNodeStatus {
}); });
} }
static toggleShowAdvancedStatus(e) {
const $element = $(e.currentTarget);
const $closestStatus = $element.siblings('.advanced-status');
$element.find('.fa').toggleClass('fa-angle-down').toggleClass('fa-angle-up');
$closestStatus.toggleClass('hidden');
}
getStatus() { getStatus() {
$.getJSON(this.endpoint, (status) => { $.getJSON(this.endpoint, (status) => {
this.setStatusIcon(status.healthy); this.setStatusIcon(status.healthy);
...@@ -49,12 +61,16 @@ class GeoNodeStatus { ...@@ -49,12 +61,16 @@ class GeoNodeStatus {
this.$dbReplicationLag.text('UNKNOWN'); this.$dbReplicationLag.text('UNKNOWN');
} }
this.$repositoriesSynced.html(`${status.repositories_synced_count}/${status.repositories_count} (${status.repositories_synced_in_percentage})`); this.$repositoriesSynced.text(`${status.repositories_synced_count}/${status.repositories_count} (${status.repositories_synced_in_percentage})`);
this.$repositoriesFailed.html(status.repositories_failed_count); this.$repositoriesFailed.text(status.repositories_failed_count);
this.$lfsObjectsSynced.html(`${status.lfs_objects_synced_count}/${status.lfs_objects_count} (${status.lfs_objects_synced_in_percentage})`); this.$lfsObjectsSynced.text(`${status.lfs_objects_synced_count}/${status.lfs_objects_count} (${status.lfs_objects_synced_in_percentage})`);
this.$attachmentsSynced.html(`${status.attachments_synced_count}/${status.attachments_count} (${status.attachments_synced_in_percentage})`); this.$attachmentsSynced.text(`${status.attachments_synced_count}/${status.attachments_count} (${status.attachments_synced_in_percentage})`);
const eventDate = gl.utils.formatDate(new Date(status.last_event_date));
const cursorDate = gl.utils.formatDate(new Date(status.cursor_last_event_date));
this.$lastEventSeen.text(`${status.last_event_id} (${eventDate})`);
this.$lastCursorEvent.text(`${status.cursor_last_event_id} (${cursorDate})`);
if (status.health === 'Healthy') { if (status.health === 'Healthy') {
this.$health.html(''); this.$health.text('');
} else { } else {
const strippedData = $('<div>').html(`${status.health}`).text(); const strippedData = $('<div>').html(`${status.health}`).text();
this.$health.html(`<code class="geo-health">${strippedData}</code>`); this.$health.html(`<code class="geo-health">${strippedData}</code>`);
...@@ -83,11 +99,11 @@ class GeoNodeStatus { ...@@ -83,11 +99,11 @@ class GeoNodeStatus {
if (healthy) { if (healthy) {
this.$healthStatus.removeClass(unhealthyClass) this.$healthStatus.removeClass(unhealthyClass)
.addClass(healthyClass) .addClass(healthyClass)
.html('Healthy'); .text('Healthy');
} else { } else {
this.$healthStatus.removeClass(healthyClass) this.$healthStatus.removeClass(healthyClass)
.addClass(unhealthyClass) .addClass(unhealthyClass)
.html('Unhealthy'); .text('Unhealthy');
} }
} }
} }
......
...@@ -29,6 +29,19 @@ ...@@ -29,6 +29,19 @@
} }
} }
.advanced-geo-node-status-container {
.btn-link {
padding-left: 0;
padding-right: 0;
border-left: 0;
border-right: 0;
.fa {
margin-left: 3px;
}
}
}
.node-info { .node-info {
color: $gl-text-color; color: $gl-text-color;
} }
......
...@@ -22,6 +22,10 @@ module Geo ...@@ -22,6 +22,10 @@ module Geo
class_name: 'Geo::RepositoriesChangedEvent', class_name: 'Geo::RepositoriesChangedEvent',
foreign_key: :repositories_changed_event_id foreign_key: :repositories_changed_event_id
def self.latest_event
order(id: :desc).first
end
def event def event
repository_created_event || repository_created_event ||
repository_updated_event || repository_updated_event ||
......
...@@ -22,6 +22,42 @@ class GeoNodeStatus ...@@ -22,6 +22,42 @@ class GeoNodeStatus
@db_replication_lag = value @db_replication_lag = value
end end
def last_event_id
@last_event_id ||= latest_event&.id
end
def last_event_id=(value)
@last_event_id = value
end
def last_event_date
@last_event_date ||= Geo::EventLog.latest_event&.created_at
end
def last_event_date=(value)
@last_event_date = value
end
def cursor_last_event_id
@cursor_last_event_id ||= cursor_last_processed&.event_id
end
def cursor_last_event_id=(value)
@cursor_last_event_id = value
end
def cursor_last_event_date
event_id = cursor_last_event_id
return unless event_id
@cursor_last_event_date ||= Geo::EventLog.find_by(id: event_id)&.created_at
end
def cursor_last_event_date=(value)
@cursor_last_event_date = value
end
def repositories_count def repositories_count
@repositories_count ||= repositories.count @repositories_count ||= repositories.count
end end
...@@ -126,4 +162,12 @@ class GeoNodeStatus ...@@ -126,4 +162,12 @@ class GeoNodeStatus
def repositories def repositories
@repositories ||= Gitlab::Geo.current_node.projects @repositories ||= Gitlab::Geo.current_node.projects
end end
def latest_event
Geo::EventLog.latest_event
end
def cursor_last_processed
Geo::EventLogState.last_processed
end
end end
...@@ -28,4 +28,9 @@ class GeoNodeStatusEntity < Grape::Entity ...@@ -28,4 +28,9 @@ class GeoNodeStatusEntity < Grape::Entity
expose :repositories_synced_in_percentage do |node| expose :repositories_synced_in_percentage do |node|
number_to_percentage(node.repositories_synced_in_percentage, precision: 2) number_to_percentage(node.repositories_synced_in_percentage, precision: 2)
end end
expose :last_event_id
expose :last_event_date
expose :cursor_last_event_id
expose :cursor_last_event_date
end end
...@@ -13,6 +13,10 @@ module Geo ...@@ -13,6 +13,10 @@ module Geo
lfs_objects_synced_count lfs_objects_synced_count
attachments_count attachments_count
attachments_synced_count attachments_synced_count
last_event_id
last_event_date
cursor_last_event_id
cursor_last_event_date
).freeze ).freeze
def call(geo_node) def call(geo_node)
......
...@@ -50,10 +50,6 @@ ...@@ -50,10 +50,6 @@
%span.help-block %span.help-block
Health Status: Health Status:
%span.js-health-status %span.js-health-status
%p
%span.help-block
Database replication lag:
%strong.node-info.js-db-replication-lag
%p %p
%span.help-block %span.help-block
Repositories synced: Repositories synced:
...@@ -70,6 +66,21 @@ ...@@ -70,6 +66,21 @@
%span.help-block %span.help-block
Attachments synced: Attachments synced:
%strong.node-info.js-attachments-synced %strong.node-info.js-attachments-synced
%p
.advanced-geo-node-status-container
.advanced-status.hidden
%span.help-block
Database replication lag:
%strong.node-info.js-db-replication-lag
%span.help-block
Last event ID seen from primary:
%strong.node-info.js-last-event-seen
%span.help-block
Last event ID processed by cursor:
%strong.node-info.js-last-cursor-event
%button.btn-link.js-advanced-geo-node-status-toggler
%span> Advanced
= icon('angle-down')
%p %p
.js-health .js-health
......
---
title: Show Geo event log and cursor data in node status page
merge_request:
author:
type: changed
...@@ -997,6 +997,10 @@ module API ...@@ -997,6 +997,10 @@ module API
expose :lfs_objects_synced_count expose :lfs_objects_synced_count
expose :attachments_count expose :attachments_count
expose :attachments_synced_count expose :attachments_synced_count
expose :last_event_id
expose :last_event_date
expose :cursor_last_event_id
expose :cursor_last_event_date
end end
class PersonalAccessToken < Grape::Entity class PersonalAccessToken < Grape::Entity
......
...@@ -267,7 +267,11 @@ describe Admin::GeoNodesController, :postgresql do ...@@ -267,7 +267,11 @@ describe Admin::GeoNodesController, :postgresql do
lfs_objects_synced_count: 123, lfs_objects_synced_count: 123,
repositories_count: 10, repositories_count: 10,
repositories_synced_count: 5, repositories_synced_count: 5,
repositories_failed_count: 0 repositories_failed_count: 0,
last_event_id: 2,
last_event_date: Time.now.iso8601,
cursor_last_event_id: 1,
cursor_last_event_date: Time.now.iso8601
) )
end end
......
...@@ -11,7 +11,11 @@ ...@@ -11,7 +11,11 @@
"db_replication_lag", "db_replication_lag",
"repositories_count", "repositories_count",
"repositories_failed_count", "repositories_failed_count",
"repositories_synced_count" "repositories_synced_count",
"last_event_id",
"last_event_date",
"cursor_last_event_id",
"cursor_last_event_date"
], ],
"properties" : { "properties" : {
"id": { "type": "integer" }, "id": { "type": "integer" },
...@@ -27,7 +31,11 @@ ...@@ -27,7 +31,11 @@
"repositories_count": { "type": "integer" }, "repositories_count": { "type": "integer" },
"repositories_failed_count": { "type": "integer" }, "repositories_failed_count": { "type": "integer" },
"repositories_synced_count": { "type": "integer" }, "repositories_synced_count": { "type": "integer" },
"repositories_synced_in_percentage": { "type": "string" } "repositories_synced_in_percentage": { "type": "string" },
"last_event_id": { "type": ["integer", "null"] },
"last_event_date": { "type": ["string", "null"] },
"cursor_last_event_id": { "type": ["integer", "null"] },
"cursor_last_event_date": { "type": ["string", "null"] }
}, },
"additionalProperties": false "additionalProperties": false
} }
...@@ -170,6 +170,34 @@ describe GeoNodeStatus do ...@@ -170,6 +170,34 @@ describe GeoNodeStatus do
end end
end end
describe '#last_event_id and #last_event_date' do
it 'returns nil when no events are available' do
expect(subject.last_event_id).to be_nil
expect(subject.last_event_date).to be_nil
end
it 'returns the latest event' do
created_at = Date.new(2017, 10, 22)
event = create(:geo_event_log, created_at: created_at)
expect(subject.last_event_id).to eq(event.id)
expect(subject.last_event_date).to eq(created_at)
end
end
describe '#cursor_last_event_id and #cursor_last_event_date' do
it 'returns nil when no events are available' do
expect(subject.cursor_last_event_id).to be_nil
expect(subject.cursor_last_event_date).to be_nil
end
it 'returns the latest event ID' do
event = create(:geo_event_log_state)
expect(subject.cursor_last_event_id).to eq(event.event_id)
end
end
context 'when no values are available' do context 'when no values are available' do
it 'returns 0 for each attribute' do it 'returns 0 for each attribute' do
allow(Gitlab::Geo::HealthCheck).to receive(:db_replication_lag).and_return(nil) allow(Gitlab::Geo::HealthCheck).to receive(:db_replication_lag).and_return(nil)
...@@ -180,6 +208,10 @@ describe GeoNodeStatus do ...@@ -180,6 +208,10 @@ describe GeoNodeStatus do
subject.repositories_count = nil subject.repositories_count = nil
subject.repositories_synced_count = nil subject.repositories_synced_count = nil
subject.repositories_failed_count = nil subject.repositories_failed_count = nil
subject.last_event_id = nil
subject.last_event_date = nil
subject.cursor_last_event_id = nil
subject.cursor_last_event_date = nil
expect(subject.db_replication_lag).to be_nil expect(subject.db_replication_lag).to be_nil
expect(subject.repositories_count).to be_zero expect(subject.repositories_count).to be_zero
...@@ -192,6 +224,10 @@ describe GeoNodeStatus do ...@@ -192,6 +224,10 @@ describe GeoNodeStatus do
expect(subject.attachments_count).to be_zero expect(subject.attachments_count).to be_zero
expect(subject.attachments_synced_count).to be_zero expect(subject.attachments_synced_count).to be_zero
expect(subject.attachments_synced_in_percentage).to be_zero expect(subject.attachments_synced_in_percentage).to be_zero
expect(subject.last_event_id).to be_nil
expect(subject.last_event_date).to be_nil
expect(subject.cursor_last_event_id).to be_nil
expect(subject.cursor_last_event_date).to be_nil
end end
end end
end end
...@@ -32,7 +32,11 @@ describe Geo::NodeStatusService do ...@@ -32,7 +32,11 @@ describe Geo::NodeStatusService do
lfs_objects_count: 100, lfs_objects_count: 100,
lfs_objects_synced_count: 50, lfs_objects_synced_count: 50,
attachments_count: 30, attachments_count: 30,
attachments_synced_count: 30 } attachments_synced_count: 30,
last_event_id: 2,
last_event_date: Time.now,
cursor_last_event_id: 1,
cursor_last_event_date: Time.now }
request = double(success?: true, parsed_response: data.stringify_keys, code: 200) request = double(success?: true, parsed_response: data.stringify_keys, code: 200)
allow(described_class).to receive(:get).and_return(request) allow(described_class).to receive(:get).and_return(request)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment