Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion splitio/admin/controllers/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ func (c *DashboardController) gatherStats() *dashboard.GlobalStats {
FeatureFlags: bundleSplitInfo(c.storages.SplitStorage),
Segments: bundleSegmentInfo(c.storages.SplitStorage, c.storages.SegmentStorage),
LargeSegments: bundleLargeSegmentInfo(c.storages.SplitStorage, c.storages.LargeSegmentStorage),
RuleBasedSegments: bundleRuleBasedInfo(c.storages.SplitStorage, c.storages.RuleBasedSegmentsStorage),
Latencies: bundleProxyLatencies(c.storages.LocalTelemetryStorage),
BackendLatencies: bundleLocalSyncLatencies(c.storages.LocalTelemetryStorage),
ImpressionsQueueSize: getImpressionSize(c.storages.ImpressionStorage),
Expand All @@ -166,6 +167,5 @@ func (c *DashboardController) gatherStats() *dashboard.GlobalStats {
LoggedMessages: errorMessages,
Uptime: int64(c.runtime.Uptime().Seconds()),
FlagSets: getFlagSetsInfo(c.storages.SplitStorage),
RuleBasedSegments: bundleRBInfo(c.storages.RuleBasedSegmentsStorage),
}
}
58 changes: 39 additions & 19 deletions splitio/admin/controllers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,45 @@ func bundleSegmentInfo(splitStorage storage.SplitStorage, segmentStorage storage
return summaries
}

func bundleRuleBasedInfo(splitStorage storage.SplitStorage, ruleBasedSegmentStorage storage.RuleBasedSegmentStorageConsumer) []dashboard.RuleBasedSegmentSummary {
names := splitStorage.RuleBasedSegmentNames()
summaries := make([]dashboard.RuleBasedSegmentSummary, 0, names.Size())

for _, name := range names.List() {
strName, ok := name.(string)
if !ok {
continue
}

ruleBased, err := ruleBasedSegmentStorage.GetRuleBasedSegmentByName(strName)
if err != nil {
continue
}

excluededSegments := make([]dashboard.ExcludedSegments, 0, len(ruleBased.Excluded.Segments))
for _, excludedSegment := range ruleBased.Excluded.Segments {
excluededSegments = append(excluededSegments, dashboard.ExcludedSegments{
Name: excludedSegment.Name,
Type: excludedSegment.Type,
})
}

if ruleBased.Excluded.Keys == nil {
ruleBased.Excluded.Keys = make([]string, 0)
}

summaries = append(summaries, dashboard.RuleBasedSegmentSummary{
Name: ruleBased.Name,
Active: ruleBased.Status == "ACTIVE",
ExcludedKeys: ruleBased.Excluded.Keys,
ExcludedSegments: excluededSegments,
LastModified: time.Unix(0, ruleBased.ChangeNumber*int64(time.Millisecond)).UTC().Format(time.UnixDate),
ChangeNumber: ruleBased.ChangeNumber,
})
}
return summaries
}

func bundleSegmentKeysInfo(name string, segmentStorage storage.SegmentStorageConsumer) []dashboard.SegmentKeySummary {

keys := segmentStorage.Keys(name)
Expand Down Expand Up @@ -316,22 +355,3 @@ func getProxyRequestCount(metrics storage.TelemetryRuntimeConsumer) (ok int64, e

return okCount, errorCount
}

func bundleRBInfo(rbStorage storage.RuleBasedSegmentsStorage) []dashboard.RBSummary {
all := rbStorage.All()
summaries := make([]dashboard.RBSummary, 0, len(all))
for _, segment := range all {
excludedSegments := make([]string, 0, len(segment.Excluded.Segments))
for _, seg := range segment.Excluded.Segments {
excludedSegments = append(excludedSegments, seg.Name)
}
summaries = append(summaries, dashboard.RBSummary{
Name: segment.Name,
ChangeNumber: segment.ChangeNumber,
Active: segment.Status == "ACTIVE",
ExcludedKeys: segment.Excluded.Keys,
ExcludedSegments: excludedSegments,
})
}
return summaries
}
23 changes: 14 additions & 9 deletions splitio/admin/controllers/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,27 @@ package controllers
import (
"testing"

"github.com/splitio/split-synchronizer/v5/splitio/admin/views/dashboard"

"github.com/splitio/go-split-commons/v8/dtos"
"github.com/splitio/go-split-commons/v8/storage/mocks"
"github.com/splitio/split-synchronizer/v5/splitio/admin/views/dashboard"
"github.com/splitio/go-toolkit/v5/datastructures/set"

"github.com/stretchr/testify/assert"
)

func TestBundleRBInfo(t *testing.T) {
split := &mocks.SplitStorageMock{}
split.On("RuleBasedSegmentNames").Return(set.NewSet("rb1", "rb2"), nil).Once()
rb := &mocks.MockRuleBasedSegmentStorage{}
rb.On("All").Return([]dtos.RuleBasedSegmentDTO{
{Name: "rb1", ChangeNumber: 1, Status: "ACTIVE", Excluded: dtos.ExcludedDTO{Keys: []string{"one"}}},
{Name: "rb2", ChangeNumber: 2, Status: "ARCHIVED"},
}, nil)
result := bundleRBInfo(rb)
rb.On("GetRuleBasedSegmentByName", "rb1").Return(&dtos.RuleBasedSegmentDTO{Name: "rb1", ChangeNumber: 1, Status: "ACTIVE", Excluded: dtos.ExcludedDTO{Keys: []string{"one"}}}, nil).Once()
rb.On("GetRuleBasedSegmentByName", "rb2").Return(&dtos.RuleBasedSegmentDTO{Name: "rb2", ChangeNumber: 2, Status: "ARCHIVED"}, nil).Once()
result := bundleRuleBasedInfo(split, rb)
assert.Len(t, result, 2)
assert.ElementsMatch(t, result, []dashboard.RBSummary{
{Name: "rb1", ChangeNumber: 1, Active: true, ExcludedKeys: []string{"one"}, ExcludedSegments: []string{}},
{Name: "rb2", ChangeNumber: 2, Active: false, ExcludedKeys: nil, ExcludedSegments: []string{}},
assert.ElementsMatch(t, result, []dashboard.RuleBasedSegmentSummary{
{Name: "rb1", ChangeNumber: 1, Active: true, ExcludedKeys: []string{"one"}, ExcludedSegments: []dashboard.ExcludedSegments{}, LastModified: "Thu Jan 1 00:00:00 UTC 1970"},
{Name: "rb2", ChangeNumber: 2, Active: false, ExcludedKeys: []string{}, ExcludedSegments: []dashboard.ExcludedSegments{}, LastModified: "Thu Jan 1 00:00:00 UTC 1970"},
})
split.AssertExpectations(t)
rb.AssertExpectations(t)
}
57 changes: 57 additions & 0 deletions splitio/admin/views/dashboard/datainspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ const dataInspector = `
</a>
</li>
{{end}}
<li role="presentation" class="">
<a href="#rule-based-segments-data" aria-controls="rule-based" role="tab" data-toggle="tab">
<span class="glyphicon" style="vertical-align:bottom" aria-hidden="true">
<svg fill="none" height="24" width="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path
d="M6 4C5.44772 4 5 4.44772 5 5V9C5 9.55228 5.44772 10 6 10H10C10.5523 10 11 9.55228 11 9V8H13V11H10V13H13V16H11V15C11 14.4477 10.5523 14 10 14H6C5.44772 14 5 14.4477 5 15V19C5 19.5523 5.44772 20 6 20H10C10.5523 20 11 19.5523 11 19V18H13V20H18C18.5523 20 19 19.5523 19 19V15C19 14.4477 18.5523 14 18 14H15V10H18C18.5523 10 19 9.55228 19 9V5C19 4.44772 18.5523 4 18 4H13V6H11V5C11 4.44772 10.5523 4 10 4H6Z"
fill="currentColor"
/>
</svg>
</span>
&nbsp;Rule-based Segments
</a>
</li>
<li role="presentation" class="">
<a href="#flag-sets-data" aria-controls="profile" role="tab" data-toggle="tab">
<span class="glyphicon" style="vertical-align:bottom" aria-hidden="true">
Expand Down Expand Up @@ -154,6 +167,50 @@ const dataInspector = `
</div>
{{end}}

<!-- RULE-BASED SEGMENT DATA -->
<div role="tabpanel" class="tab-pane" id="rule-based-segments-data">
<div class="row">
<div class="col-md-12">
<div class="bg-primary metricBox">
<!-- <h4>Rule-based Segments in proxy</h4> -->
<div class="row">
<div class="col-md-4 col-md-offset-8">
<div class="input-group">
<input type="text" id="filterRuleBasedSegmentNameInput" class="form-control" placeholder="Filter by Rule-based Segment name">
<span class="input-group-btn">
<button class="btn btn-default" type="button" onclick="javascript:filterRuleBasedSegments();">
<span class="glyphicon glyphicon-filter" aria-hidden="true"></span>
</button>
<button class="btn btn-default" type="button" onclick="javascript:resetFilterRuleBasedSegments();">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table id="rule_based_segment_rows" class="table table-condensed table-hover">
<thead>
<tr>
<th>Rule-based segment</th>
<th>Status</th>
<th>Excluded Keys</th>
<th>Excluded segments</th>
<th>Last Modified</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>


<!-- FLAG SETS DATA -->
<div role="tabpanel" class="tab-pane" id="flag-sets-data">
<div class="row">
Expand Down
54 changes: 54 additions & 0 deletions splitio/admin/views/dashboard/js.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,23 @@ const mainScript = `
}
});
}

function resetFilterRuleBasedSegments(){
$("tr.ruleBasedItem").removeClass("filterDisplayNone");
$("#filterRuleBasedSegmentNameInput").val("");
}

function filterRuleBasedSegments(){
$("tr.ruleBasedItem").removeClass("filterDisplayNone");
var filter = $("#filterRuleBasedSegmentNameInput").val();
$("tr.ruleBasedItem").each(function() {
$this = $(this);
var ruleBasedName = $this.find("span.ruleBasedItemName").html();
if (ruleBasedName.indexOf(filter.trim()) == -1) {
$this.addClass("filterDisplayNone");
}
});
}

$(function () {
$('[data-toggle="tooltip"]').tooltip()
Expand Down Expand Up @@ -255,6 +272,42 @@ const mainScript = `
}
};

function formatRuleBasedSegment(ruleBasedSegment) {
var excludedSegments = Array.isArray(ruleBasedSegment.excludedSegments)
? ruleBasedSegment.excludedSegments
: [];

var excludedSegmentsHtml = excludedSegments.length
? excludedSegments.map(function(seg, i) {
var segName = seg && seg.name ? seg.name : 'Unnamed';
var segType = seg && seg.type ? seg.type : 'Unknown';
var separator = i < excludedSegments.length - 1 ? ', ' : '';
return '<span>' + segName + ' (' + segType + ')</span>' + separator;
}).join('')
: '—';

return (
'<tr class="ruleBasedItem">' +
'<td><span class="ruleBasedItemName">' + ruleBasedSegment.name + '</span></td>' +
(ruleBasedSegment.active
? '<td class="">ACTIVE</td>'
: '<td class="danger">ARCHIVED</td>') +
'<td>' + (ruleBasedSegment.excludedKeys || '') + '</td>' +
'<td>' + excludedSegmentsHtml + '</td>' +
'<td>' + (ruleBasedSegment.cn || '') + '</td>' +
'</tr>\n'
);
}

function updateRuleBasedSegments(ruleBasedSegments) {
ruleBasedSegments.sort((a, b) => parseFloat(b.changeNumber) - parseFloat(a.changeNumber));
const formatted = ruleBasedSegments.map(formatRuleBasedSegment).join('\n');
if (document.getElementById('filterRuleBasedSegmentNameInput').value.length == 0) {
$('#rule_based_segment_rows tbody').empty();
$('#rule_based_segment_rows tbody').append(formatted);
}
};

function formatFlagSet(flagSet) {
return (
'<tr class="flagSetItem">' +
Expand Down Expand Up @@ -443,6 +496,7 @@ const mainScript = `
updateFeatureFlags(stats.featureFlags);
updateSegments(stats.segments);
updateLargeSegments(stats.largesegments);
updateRuleBasedSegments(stats.rulebasedsegments)
updateLogEntries(stats.loggedMessages);
updateFlagSets(stats.flagSets)

Expand Down
62 changes: 34 additions & 28 deletions splitio/admin/views/dashboard/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,26 +89,26 @@ type RootObject struct {

// GlobalStats runtime stats used to render the dashboard
type GlobalStats struct {
BackendTotalRequests int64 `json:"backendTotalRequests"`
RequestsOk int64 `json:"requestsOk"`
RequestsErrored int64 `json:"requestsErrored"`
BackendRequestsOk int64 `json:"backendRequestsOk"`
BackendRequestsErrored int64 `json:"backendRequestsErrored"`
SdksTotalRequests int64 `json:"sdksTotalRequests"`
LoggedErrors int64 `json:"loggedErrors"`
LoggedMessages []string `json:"loggedMessages"`
FeatureFlags []SplitSummary `json:"featureFlags"`
Segments []SegmentSummary `json:"segments"`
LargeSegments []LargeSegmentSummary `json:"largesegments"`
Latencies []ChartJSData `json:"latencies"`
BackendLatencies []ChartJSData `json:"backendLatencies"`
ImpressionsQueueSize int64 `json:"impressionsQueueSize"`
ImpressionsLambda float64 `json:"impressionsLambda"`
EventsQueueSize int64 `json:"eventsQueueSize"`
EventsLambda float64 `json:"eventsLambda"`
Uptime int64 `json:"uptime"`
FlagSets []FlagSetsSummary `json:"flagSets"`
RuleBasedSegments []RBSummary `json:"ruleBasedSegments"`
BackendTotalRequests int64 `json:"backendTotalRequests"`
RequestsOk int64 `json:"requestsOk"`
RequestsErrored int64 `json:"requestsErrored"`
BackendRequestsOk int64 `json:"backendRequestsOk"`
BackendRequestsErrored int64 `json:"backendRequestsErrored"`
SdksTotalRequests int64 `json:"sdksTotalRequests"`
LoggedErrors int64 `json:"loggedErrors"`
LoggedMessages []string `json:"loggedMessages"`
FeatureFlags []SplitSummary `json:"featureFlags"`
Segments []SegmentSummary `json:"segments"`
LargeSegments []LargeSegmentSummary `json:"largesegments"`
RuleBasedSegments []RuleBasedSegmentSummary `json:"rulebasedsegments"`
Latencies []ChartJSData `json:"latencies"`
BackendLatencies []ChartJSData `json:"backendLatencies"`
ImpressionsQueueSize int64 `json:"impressionsQueueSize"`
ImpressionsLambda float64 `json:"impressionsLambda"`
EventsQueueSize int64 `json:"eventsQueueSize"`
EventsLambda float64 `json:"eventsLambda"`
Uptime int64 `json:"uptime"`
FlagSets []FlagSetsSummary `json:"flagSets"`
}

// SplitSummary encapsulates a minimalistic view of feature flag properties to be presented in the dashboard
Expand Down Expand Up @@ -138,6 +138,20 @@ type LargeSegmentSummary struct {
LastModified string `json:"cn"`
}

type RuleBasedSegmentSummary struct {
Name string `json:"name"`
Active bool `json:"active"`
ExcludedKeys []string `json:"excludedKeys"`
ExcludedSegments []ExcludedSegments `json:"excludedSegments"`
LastModified string `json:"cn"`
ChangeNumber int64 `json:"changeNumber"`
}

type ExcludedSegments struct {
Name string `json:"name"`
Type string `json:"type"`
}

// SegmentKeySummary encapsulates basic information associated to the key in proxy mode
// (fields other than name are empty when running as producer
type SegmentKeySummary struct {
Expand All @@ -152,14 +166,6 @@ type FlagSetsSummary struct {
FeatureFlags string `json:"featureFlags"`
}

type RBSummary struct {
Name string `json:"name"`
ChangeNumber int64 `json:"cn"`
Active bool `json:"active"`
ExcludedKeys []string `json:"excludedKeys"`
ExcludedSegments []string `json:"excludedSegments"`
}

// RGBA bundles input to CSS's rgba function
type RGBA struct {
Red int32
Expand Down
2 changes: 1 addition & 1 deletion splitio/commitversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ This file is created automatically, please do not edit
*/

// CommitVersion is the version of the last commit previous to release
const CommitVersion = "35fdde3"
const CommitVersion = "8fd26d7"
6 changes: 0 additions & 6 deletions splitio/proxy/storage/rulebasedsegments.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,6 @@ func (p *ProxyRuleBasedSegmentsStorageImpl) ChangesSince(since int64) (*dtos.Rul
all = append(all, *rbSegments)
}
return &dtos.RuleBasedSegmentsDTO{Since: since, Till: till, RuleBasedSegments: all}, nil

// if since > -1 {
// return &dtos.RuleBasedSegmentsDTO{Since: since, Till: since, RuleBasedSegments: []dtos.RuleBasedSegmentDTO{}}, nil
// }
// cn, _ := p.snapshot.ChangeNumber()
// return &dtos.RuleBasedSegmentsDTO{Since: since, Till: cn, RuleBasedSegments: p.snapshot.All()}, nil
}

// All call is forwarded to the snapshot
Expand Down
Loading
Loading