rancher 容器日志组件分析

举报
拿我格子衫来 发表于 2022/03/18 00:19:28 2022/03/18
【摘要】 \app\components\container-logs\template.hbs 使用的websock   template.hbs <h2> <i class="icon icon-file"></i> {{t 'containerLogs.title'}} {{#if ...

\app\components\container-logs\template.hbs

使用的websock

 

template.hbs


  
  1. <h2>
  2. <i class="icon icon-file"></i> {{t 'containerLogs.title'}}
  3. {{#if displayName}}
  4. {{displayName}}
  5. {{else if (gt instance.containers.length 1)}}
  6. <div class="container-select">
  7. {{new-select
  8. classNames="form-control"
  9. optionValuePath="name"
  10. optionLabelPath="name"
  11. content=instance.containers
  12. value=containerName
  13. }}
  14. </div>
  15. {{else}}
  16. {{containerName}}
  17. {{/if}}
  18. <div class="console-status text-muted pull-right">{{t (concat 'containerLogs.status.' status)}}</div>
  19. </h2>
  20. {{#if showProtip}}
  21. <div class="protip">
  22. {{t 'containerLogs.protip' key=alternateLabel}}
  23. </div>
  24. {{/if}}
  25. <pre class="log-body {{if wrapLines 'wrap-lines'}}">
  26. </pre>
  27. {{yield}}
  28. <div class="footer-actions">
  29. <div class="checkbox pt-10 text-left" style="position: absolute; top: -2px">
  30. <label class="block">
  31. {{input type="checkbox" checked=wrapLines}}
  32. {{t 'containerLogs.wrapLines'}}
  33. </label>
  34. <label class="block">
  35. {{input type="checkbox" checked=isPrevious}}
  36. {{t 'containerLogs.previous'}}
  37. </label>
  38. </div>
  39. <button {{action "scrollToTop"}} class="btn bg-default">{{t 'containerLogs.scrollTop'}}</button>
  40. <button {{action "followLog"}} class="btn bg-default scroll-bottom">{{t 'containerLogs.scrollBottom'}}</button>
  41. <button {{action "download"}} class="btn bg-default">{{t 'containerLogs.download'}}</button>
  42. <button {{action "clear"}} class="btn bg-default">{{t 'containerLogs.clear'}}</button>
  43. <button {{action "cancel"}} class="btn bg-primary">{{t 'generic.closeModal'}}</button>
  44. </div>

 

 

 

component.js


  
  1. import { next } from '@ember/runloop';
  2. import { set, setProperties, get, observer } from '@ember/object';
  3. import { inject as service } from '@ember/service';
  4. import Component from '@ember/component';
  5. import Util from 'ui/utils/util';
  6. import { alternateLabel } from 'ui/utils/platform';
  7. import layout from './template';
  8. import C from 'ui/utils/constants';
  9. import { downloadFile } from 'shared/utils/download-files';
  10. import $ from 'jquery';
  11. import { on } from '@ember/object/evented';
  12. const LINES = 500;
  13. var AnsiUp = null;
  14. export default Component.extend({
  15. scope: service(),
  16. prefs: service(),
  17. layout,
  18. instance: null,
  19. alternateLabel,
  20. showProtip: true,
  21. classNames: 'container-log',
  22. status: 'connecting',
  23. containerName: null,
  24. socket: null,
  25. wrapLines: null,
  26. isFollow: true,
  27. followTimer: null,
  28. isPrevious: false,
  29. init() {
  30. this._super(...arguments);
  31. if (AnsiUp) {
  32. this._bootstrap();
  33. } else {
  34. import('ansi_up').then( (module) => {
  35. AnsiUp = module.default;
  36. this._bootstrap();
  37. });
  38. }
  39. },
  40. didInsertElement() {
  41. this._super();
  42. next(this, () => {
  43. const body = $('.log-body');
  44. let lastScrollTop = 0;
  45. body.scroll(() => {
  46. const scrollTop = body[0].scrollTop;
  47. if ( lastScrollTop > scrollTop ) {
  48. set(this, 'isFollow', false);
  49. }
  50. lastScrollTop = scrollTop;
  51. });
  52. var btn = $('.scroll-bottom')[0]; // eslint-disable-line
  53. if ( btn ) {
  54. btn.focus();
  55. }
  56. });
  57. },
  58. willDestroyElement() {
  59. clearInterval(get(this, 'followTimer'));
  60. this.disconnect();
  61. this._super();
  62. },
  63. actions: {
  64. download() {
  65. const ignore = function(el, sel){
  66. return el.clone().find( sel || '>*' ).remove().end();
  67. };
  68. const log = $('.log-body').children('.log-msg');
  69. let stripped = '';
  70. log.each((i, e) => {
  71. stripped += `${ ignore($(e), 'span').text() } \n`;
  72. });
  73. downloadFile('container.log', stripped);
  74. },
  75. cancel() {
  76. this.disconnect();
  77. if (this.dismiss) {
  78. this.dismiss();
  79. }
  80. },
  81. clear() {
  82. var body = $('.log-body')[0];
  83. if (body) {
  84. body.innerHTML = '';
  85. body.scrollTop = 0;
  86. }
  87. },
  88. scrollToTop() {
  89. $('.log-body').animate({ scrollTop: '0px' });
  90. },
  91. followLog() {
  92. set(this, 'isFollow', true);
  93. this.send('scrollToBottom');
  94. },
  95. scrollToBottom() {
  96. var body = $('.log-body');
  97. body.stop().animate({ scrollTop: `${ body[0].scrollHeight + 1000 }px` });
  98. },
  99. },
  100. wrapLinesDidChange: observer('wrapLines', function() {
  101. set(this, `prefs.${ C.PREFS.WRAP_LINES }`, get(this, 'wrapLines'));
  102. }),
  103. watchReconnect: on('init', observer('containerName', 'isPrevious', function() {
  104. this.disconnect();
  105. this.send('clear');
  106. if (this.containerName) {
  107. this.exec();
  108. }
  109. })),
  110. _bootstrap() {
  111. setProperties(this, {
  112. wrapLines: !!get(this, `prefs.${ C.PREFS.WRAP_LINES }`),
  113. containerName: get(this, 'containerName') || get(this, 'instance.containers.firstObject.name'),
  114. });
  115. this._initTimer();
  116. },
  117. _initTimer() {
  118. const followTimer = setInterval(() => {
  119. if ( get(this, 'isFollow') ) {
  120. this.send('scrollToBottom');
  121. }
  122. }, 1000);
  123. set(this, 'followTimer', followTimer);
  124. },
  125. exec() {
  126. var instance = get(this, 'instance');
  127. const clusterId = get(this, 'scope.currentCluster.id');
  128. const namespaceId = get(instance, 'namespaceId');
  129. const podName = get(instance, 'name');
  130. const containerName = get(this, 'containerName');
  131. const scheme = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
  132. let url = `${ scheme }${ window.location.host }/k8s/clusters/${ clusterId }/api/v1/namespaces/${ namespaceId }/pods/${ podName }/log`;
  133. url += `?container=${ encodeURIComponent(containerName) }&tailLines=${ LINES }&follow=true&timestamps=true&previous=${ get(this, 'isPrevious') }`;
  134. this.connect(url);
  135. },
  136. connect(url) {
  137. var socket = new WebSocket(url, 'base64.binary.k8s.io');
  138. set(this, 'socket', socket);
  139. var body = null;
  140. set(this, 'status', 'initializing');
  141. socket.onopen = () => {
  142. set(this, 'status', 'connected');
  143. };
  144. socket.onmessage = (message) => {
  145. body = $('.log-body')[0];
  146. let ansiup = new AnsiUp;
  147. set(this, 'status', 'connected');
  148. const data = AWS.util.base64.decode(message.data).toString();
  149. let html = '';
  150. data.trim().split(/\n/)
  151. .filter((line) => line)
  152. .forEach((line) => {
  153. var match = line.match(/^\[?([^ \]]+)\]?\s?/);
  154. var dateStr = '';
  155. var msg = '';
  156. if (match && this.isDate(new Date(match[1]))) {
  157. var date = new Date(match[1]);
  158. msg = line.substr(match[0].length);
  159. dateStr = `<span class="log-date">${ Util.escapeHtml(date.toLocaleDateString()) } ${ Util.escapeHtml(date.toLocaleTimeString()) } </span>`;
  160. } else {
  161. msg = line;
  162. }
  163. // @@TODO@@ - 10-13-17 - needed to remove the escaping here because it was being double escaped but double verify that its acutally being escaped
  164. html += `<div class="log-msg log-combined">${
  165. dateStr
  166. }${ ansiup.ansi_to_html(msg)
  167. }</div>`
  168. });
  169. body.insertAdjacentHTML('beforeend', html);
  170. };
  171. socket.onclose = () => {
  172. if (this.isDestroyed || this.isDestroying) {
  173. return;
  174. }
  175. set(this, 'status', 'disconnected');
  176. };
  177. },
  178. disconnect() {
  179. set(this, 'status', 'closed');
  180. var socket = get(this, 'socket');
  181. if (socket) {
  182. socket.close();
  183. set(this, 'socket', null);
  184. }
  185. },
  186. isDate(date) {
  187. return new Date(date) !== 'Invalid Date' && !isNaN(new Date(date))
  188. },
  189. });

 

文章来源: fizzz.blog.csdn.net,作者:拿我格子衫来,版权归原作者所有,如需转载,请联系作者。

原文链接:fizzz.blog.csdn.net/article/details/108662784

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。