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 {
this.$repositoriesFailed = $('.js-repositories-failed', this.$status);
this.$lfsObjectsSynced = $('.js-lfs-objects-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.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({
callback: this.getStatus.bind(this),
......@@ -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() {
$.getJSON(this.endpoint, (status) => {
this.setStatusIcon(status.healthy);
......@@ -49,12 +61,16 @@ class GeoNodeStatus {
this.$dbReplicationLag.text('UNKNOWN');
}
this.$repositoriesSynced.html(`${status.repositories_synced_count}/${status.repositories_count} (${status.repositories_synced_in_percentage})`);
this.$repositoriesFailed.html(status.repositories_failed_count);
this.$lfsObjectsSynced.html(`${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.$repositoriesSynced.text(`${status.repositories_synced_count}/${status.repositories_count} (${status.repositories_synced_in_percentage})`);
this.$repositoriesFailed.text(status.repositories_failed_count);
this.$lfsObjectsSynced.text(`${status.lfs_objects_synced_count}/${status.lfs_objects_count} (${status.lfs_objects_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') {
this.$health.html('');
this.$health.text('');
} else {
const strippedData = $('<div>').html(`${status.health}`).text();
this.$health.html(`<code class="geo-health">${strippedData}</code>`);
......@@ -83,11 +99,11 @@ class GeoNodeStatus {
if (healthy) {
this.$healthStatus.removeClass(unhealthyClass)
.addClass(healthyClass)
.html('Healthy');
.text('Healthy');
} else {
this.$healthStatus.removeClass(healthyClass)
.addClass(unhealthyClass)
.html('Unhealthy');
.text('Unhealthy');
}
}
}
......
......@@ -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 {
color: $gl-text-color;
}
......
......@@ -22,6 +22,10 @@ module Geo
class_name: 'Geo::RepositoriesChangedEvent',
foreign_key: :repositories_changed_event_id
def self.latest_event
order(id: :desc).first
end
def event
repository_created_event ||
repository_updated_event ||
......
......@@ -22,6 +22,42 @@ class GeoNodeStatus
@db_replication_lag = value
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
@repositories_count ||= repositories.count
end
......@@ -126,4 +162,12 @@ class GeoNodeStatus
def repositories
@repositories ||= Gitlab::Geo.current_node.projects
end
def latest_event
Geo::EventLog.latest_event
end
def cursor_last_processed
Geo::EventLogState.last_processed
end
end
......@@ -28,4 +28,9 @@ class GeoNodeStatusEntity < Grape::Entity
expose :repositories_synced_in_percentage do |node|
number_to_percentage(node.repositories_synced_in_percentage, precision: 2)
end
expose :last_event_id
expose :last_event_date
expose :cursor_last_event_id
expose :cursor_last_event_date
end
......@@ -13,6 +13,10 @@ module Geo
lfs_objects_synced_count
attachments_count
attachments_synced_count
last_event_id
last_event_date
cursor_last_event_id
cursor_last_event_date
).freeze
def call(geo_node)
......
......@@ -50,10 +50,6 @@
%span.help-block
Health Status:
%span.js-health-status
%p
%span.help-block
Database replication lag:
%strong.node-info.js-db-replication-lag
%p
%span.help-block
Repositories synced:
......@@ -70,6 +66,21 @@
%span.help-block
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
.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
expose :lfs_objects_synced_count
expose :attachments_count
expose :attachments_synced_count
expose :last_event_id
expose :last_event_date
expose :cursor_last_event_id
expose :cursor_last_event_date
end
class PersonalAccessToken < Grape::Entity
......
......@@ -267,7 +267,11 @@ describe Admin::GeoNodesController, :postgresql do
lfs_objects_synced_count: 123,
repositories_count: 10,
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
......
......@@ -11,7 +11,11 @@
"db_replication_lag",
"repositories_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" : {
"id": { "type": "integer" },
......@@ -27,7 +31,11 @@
"repositories_count": { "type": "integer" },
"repositories_failed_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
}
......@@ -170,6 +170,34 @@ describe GeoNodeStatus do
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
it 'returns 0 for each attribute' do
allow(Gitlab::Geo::HealthCheck).to receive(:db_replication_lag).and_return(nil)
......@@ -180,6 +208,10 @@ describe GeoNodeStatus do
subject.repositories_count = nil
subject.repositories_synced_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.repositories_count).to be_zero
......@@ -192,6 +224,10 @@ describe GeoNodeStatus do
expect(subject.attachments_count).to be_zero
expect(subject.attachments_synced_count).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
......@@ -32,7 +32,11 @@ describe Geo::NodeStatusService do
lfs_objects_count: 100,
lfs_objects_synced_count: 50,
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)
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