vitess.io/vitess@v0.16.2/go/vt/srvtopo/status.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package srvtopo
    18  
    19  import (
    20  	"context"
    21  	"html/template"
    22  	"sort"
    23  	"time"
    24  
    25  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    26  )
    27  
    28  // TopoTemplate is the HTML to use to display the
    29  // ResilientServerCacheStatus object
    30  const TopoTemplate = `
    31  <style>
    32    table {
    33      border-collapse: collapse;
    34    }
    35    td, th {
    36      border: 1px solid #999;
    37      padding: 0.2rem;
    38    }
    39  </style>
    40  <table>
    41    <tr>
    42      <th colspan="4">SrvKeyspace Names Cache</th>
    43    </tr>
    44    <tr>
    45      <th>Cell</th>
    46      <th>SrvKeyspace Names</th>
    47      <th>TTL</th>
    48      <th>Error</th>
    49    </tr>
    50    {{range $i, $skn := .SrvKeyspaceNames}}
    51    <tr>
    52      <td>{{github_com_vitessio_vitess_vtctld_srv_cell $skn.Cell}}</td>
    53      <td>{{range $j, $value := $skn.Value}}{{github_com_vitessio_vitess_vtctld_srv_keyspace $skn.Cell $value}}&nbsp;{{end}}</td>
    54      <td>{{github_com_vitessio_vitess_srvtopo_ttl_time $skn.ExpirationTime}}</td>
    55      <td>{{if $skn.LastError}}({{github_com_vitessio_vitess_srvtopo_time_since $skn.LastQueryTime}}Ago) {{$skn.LastError}}{{end}}</td>
    56    </tr>
    57    {{end}}
    58  </table>
    59  <br>
    60  <table>
    61    <tr>
    62      <th colspan="5">SrvKeyspace Cache</th>
    63    </tr>
    64    <tr>
    65      <th>Cell</th>
    66      <th>Keyspace</th>
    67      <th>SrvKeyspace</th>
    68      <th>TTL</th>
    69      <th>Error</th>
    70    </tr>
    71    {{range $i, $sk := .SrvKeyspaces}}
    72    <tr>
    73      <td>{{github_com_vitessio_vitess_vtctld_srv_cell $sk.Cell}}</td>
    74      <td>{{github_com_vitessio_vitess_vtctld_srv_keyspace $sk.Cell $sk.Keyspace}}</td>
    75      <td>{{$sk.StatusAsHTML}}</td>
    76      <td>{{github_com_vitessio_vitess_srvtopo_ttl_time $sk.ExpirationTime}}</td>
    77      <td>{{if $sk.LastError}}({{github_com_vitessio_vitess_srvtopo_time_since $sk.LastErrorTime}} Ago) {{$sk.LastError}}{{end}}</td>
    78    </tr>
    79    {{end}}
    80  </table>
    81  `
    82  
    83  // The next few structures and methods are used to get a displayable
    84  // version of the cache in a status page.
    85  
    86  // SrvKeyspaceNamesCacheStatus is the current value for SrvKeyspaceNames
    87  type SrvKeyspaceNamesCacheStatus struct {
    88  	Cell           string
    89  	Value          []string
    90  	ExpirationTime time.Time
    91  	LastQueryTime  time.Time
    92  	LastError      error
    93  	LastErrorCtx   context.Context
    94  }
    95  
    96  // SrvKeyspaceNamesCacheStatusList is used for sorting
    97  type SrvKeyspaceNamesCacheStatusList []*SrvKeyspaceNamesCacheStatus
    98  
    99  // Len is part of sort.Interface
   100  func (skncsl SrvKeyspaceNamesCacheStatusList) Len() int {
   101  	return len(skncsl)
   102  }
   103  
   104  // Less is part of sort.Interface
   105  func (skncsl SrvKeyspaceNamesCacheStatusList) Less(i, j int) bool {
   106  	return skncsl[i].Cell < skncsl[j].Cell
   107  }
   108  
   109  // Swap is part of sort.Interface
   110  func (skncsl SrvKeyspaceNamesCacheStatusList) Swap(i, j int) {
   111  	skncsl[i], skncsl[j] = skncsl[j], skncsl[i]
   112  }
   113  
   114  // SrvKeyspaceCacheStatus is the current value for a SrvKeyspace object
   115  type SrvKeyspaceCacheStatus struct {
   116  	Cell           string
   117  	Keyspace       string
   118  	Value          *topodatapb.SrvKeyspace
   119  	ExpirationTime time.Time
   120  	LastErrorTime  time.Time
   121  	LastError      error
   122  }
   123  
   124  // StatusAsHTML returns an HTML version of our status.
   125  // It works best if there is data in the cache.
   126  func (st *SrvKeyspaceCacheStatus) StatusAsHTML() template.HTML {
   127  	if st.Value == nil {
   128  		return template.HTML("No Data")
   129  	}
   130  
   131  	result := "<b>Partitions:</b><br>"
   132  	for _, keyspacePartition := range st.Value.Partitions {
   133  		result += "&nbsp;<b>" + keyspacePartition.ServedType.String() + ":</b>"
   134  		for _, shard := range keyspacePartition.ShardReferences {
   135  			result += "&nbsp;" + shard.Name
   136  		}
   137  		result += "<br>"
   138  	}
   139  
   140  	if len(st.Value.ServedFrom) > 0 {
   141  		result += "<b>ServedFrom:</b><br>"
   142  		for _, sf := range st.Value.ServedFrom {
   143  			result += "&nbsp;<b>" + sf.TabletType.String() + ":</b>&nbsp;" + sf.Keyspace + "<br>"
   144  		}
   145  	}
   146  
   147  	return template.HTML(result)
   148  }
   149  
   150  // SrvKeyspaceCacheStatusList is used for sorting
   151  type SrvKeyspaceCacheStatusList []*SrvKeyspaceCacheStatus
   152  
   153  // Len is part of sort.Interface
   154  func (skcsl SrvKeyspaceCacheStatusList) Len() int {
   155  	return len(skcsl)
   156  }
   157  
   158  // Less is part of sort.Interface
   159  func (skcsl SrvKeyspaceCacheStatusList) Less(i, j int) bool {
   160  	return skcsl[i].Cell+"."+skcsl[i].Keyspace <
   161  		skcsl[j].Cell+"."+skcsl[j].Keyspace
   162  }
   163  
   164  // Swap is part of sort.Interface
   165  func (skcsl SrvKeyspaceCacheStatusList) Swap(i, j int) {
   166  	skcsl[i], skcsl[j] = skcsl[j], skcsl[i]
   167  }
   168  
   169  // ResilientServerCacheStatus has the full status of the cache
   170  type ResilientServerCacheStatus struct {
   171  	SrvKeyspaceNames SrvKeyspaceNamesCacheStatusList
   172  	SrvKeyspaces     SrvKeyspaceCacheStatusList
   173  }
   174  
   175  // CacheStatus returns a displayable version of the cache
   176  func (server *ResilientServer) CacheStatus() *ResilientServerCacheStatus {
   177  	result := &ResilientServerCacheStatus{
   178  		SrvKeyspaceNames: server.srvKeyspaceNamesCacheStatus(),
   179  		SrvKeyspaces:     server.srvKeyspaceCacheStatus(),
   180  	}
   181  	sort.Sort(result.SrvKeyspaceNames)
   182  	sort.Sort(result.SrvKeyspaces)
   183  	return result
   184  }
   185  
   186  // Returns the ttl for the cached entry or "Expired" if it is in the past
   187  func ttlTime(expirationTime time.Time) template.HTML {
   188  	ttl := time.Until(expirationTime).Round(time.Second)
   189  	if ttl < 0 {
   190  		return template.HTML("<b>Expired</b>")
   191  	}
   192  	return template.HTML(ttl.String())
   193  }
   194  
   195  func timeSince(t time.Time) template.HTML {
   196  	return template.HTML(time.Since(t).Round(time.Second).String())
   197  }
   198  
   199  // StatusFuncs is required for CacheStatus) to work properly.
   200  // We don't register them inside servenv directly so we don't introduce
   201  // a dependency here.
   202  var StatusFuncs = template.FuncMap{
   203  	"github_com_vitessio_vitess_srvtopo_ttl_time":   ttlTime,
   204  	"github_com_vitessio_vitess_srvtopo_time_since": timeSince,
   205  }