solid_apm 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d90f515a42a990a08a88c44bb8146dfe87176c81ad8584bcf7e4a29083316c2e
4
- data.tar.gz: a92fd226a1a96882700cea025afa4ba1d8d2356cce2dd621701149e612e9fe2c
3
+ metadata.gz: 2980cc185b4e779e37f5a2b1ef323f3bddc9453076725d992a3d7641e54ae370
4
+ data.tar.gz: 9ef8518d90d7351f17001d428c79dba5c7ebecd890c642f47ae2fd1e744f5591
5
5
  SHA512:
6
- metadata.gz: 3d0af12fc21edcb8117da1f466b440c0241ccb6995f174abf50e09e77e7fa8a32a36b1c0aa2559d55af6238dce318101bd42e38f06536f28d75499c8bdbc0a11
7
- data.tar.gz: 5b0829667356213cda1c572c8386f902b2054143bf66b2252f2e047d9590345acaea13c4902b7dee3c04b42e6dbe73f2449d7a30197afdf5a3989628d3d1ef8b
6
+ metadata.gz: b9af1a90d9603e05b5436bdcb420c31dfe7156d4768f261772a6e602f160385a6c7af60e8b08bb2050df4151a27703858c184bf271bfeac69d05de5b6efa344f
7
+ data.tar.gz: 48fb657be11a65ae888235a88ac8794a1ecdf8ea4863d5c7cdb1c3e292cabb04917b1b109d1c157099550a53931d1272fa0362ffbddb433fb8e4f839ce8cf93c
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  require "bundler/setup"
2
2
 
3
- APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
3
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
4
4
  load "rails/tasks/engine.rake"
5
5
 
6
6
  load "rails/tasks/statistics.rake"
@@ -8,4 +8,3 @@ window.Stimulus = Application.start();
8
8
 
9
9
  // require "./controllers/spans-chart_controller"
10
10
  // import "./controllers/spans-chart_controller.js"
11
- // import "./controllers/transaction-chart_controller"
@@ -3,22 +3,41 @@
3
3
  module SolidApm
4
4
  class TransactionsController < ApplicationController
5
5
  TransactionAggregation = Struct.new(:name, :tmp, :latency, :percentile_95, :impact)
6
+ private_constant :TransactionAggregation
6
7
 
7
8
  def index
8
- @aggregated_transactions = Transaction.where(created_at: from_to_range).group_by(&:name)
9
- @aggregated_transactions.transform_values! do |transactions|
10
- latency = transactions.map(&:duration).sum / transactions.size
11
- tmp = transactions.size.to_f / ((from_to_range.end - from_to_range.begin) / 60).to_i
9
+ if from_to_range.end < from_to_range.begin
10
+ flash[:error] = 'Invalid time range'
11
+ redirect_to transactions_path
12
+ return
13
+ end
14
+
15
+ @transactions_scope = Transaction.where(timestamp: from_to_range)
16
+ if params[:name].present?
17
+ @transactions_scope = @transactions_scope.where(name: params[:name])
18
+ end
19
+ transaction_names = @transactions_scope.distinct.pluck(:name)
20
+ latency_95p = @transactions_scope.group(:name).percentile(:duration, 0.95)
21
+ latency_median = @transactions_scope.group(:name).median(:duration)
22
+ tmp_dict = @transactions_scope.group(:name).group_by_minute(:timestamp, series: false).count.each_with_object({}) do |(k, v), h|
23
+ current_value = h[k.first] ||= 0
24
+ h[k.first] = v if v > current_value
25
+ end
26
+
27
+ @aggregated_transactions = transaction_names.each_with_object({}) do |transaction_name, h|
28
+ latency = latency_median[transaction_name]
29
+ tmp = tmp_dict[transaction_name]
12
30
  impact = latency * tmp
13
- percentile_95 = transactions[transactions.size * 0.95].duration
14
- TransactionAggregation.new(
15
- transactions.first.name,
31
+ h[transaction_name] = TransactionAggregation.new(
32
+ transaction_name,
16
33
  tmp,
17
34
  latency,
18
- percentile_95,
35
+ latency_95p[transaction_name],
19
36
  impact
20
37
  )
21
38
  end
39
+
40
+ return if @aggregated_transactions.empty?
22
41
  # Find the maximum and minimum impact values
23
42
  max_impact = @aggregated_transactions.values.max_by(&:impact).impact
24
43
  min_impact = @aggregated_transactions.values.min_by(&:impact).impact
@@ -30,32 +49,15 @@ module SolidApm
30
49
  aggregation.impact = normalized_impact.to_i || 0
31
50
  end
32
51
  @aggregated_transactions = @aggregated_transactions.sort_by { |_, v| -v.impact }.to_h
33
- end
34
52
 
35
- def show_by_name
36
- @transactions = Transaction.where(name: params[:name]).order(timestamp: :desc).limit(20)
37
- end
38
-
39
- def show
40
- @transaction = Transaction.find(params[:id])
53
+ scope = @transactions_scope.group_by_second(:timestamp, n: n_intervals_seconds(from_to_range))
54
+ @throughput_data = scope.count
55
+ @latency_data = scope.median(:duration).transform_values(&:to_i)
41
56
  end
42
57
 
43
58
  def spans
44
- @transaction = Transaction.find(params[:id])
45
- @spans = @transaction.spans
46
- render json: @spans
47
- end
48
-
49
- def count_time_aggregations
50
- scope = Transaction.all.order(timestamp: :desc)
51
- .where(created_at: from_to_range)
52
-
53
-
54
- if params[:name].present?
55
- scope = scope.where(name: params[:name])
56
- end
57
-
58
- render json: aggregate(scope.select(:id, :created_at).find_each, from_to_range, intervals_count: 20).transform_values!(&:count)
59
+ @transaction = Transaction.find_by!(uuid: params[:uuid])
60
+ @transaction.spans.to_a
59
61
  end
60
62
 
61
63
  private
@@ -64,10 +66,19 @@ module SolidApm
64
66
  params[:from_value] ||= 60
65
67
  params[:from_unit] ||= 'minutes'
66
68
  from = params[:from_value].to_i.public_send(params[:from_unit].to_sym).ago
67
- to = Time.current
69
+ params[:to_value] ||= 1
70
+ params[:to_unit] ||= 'seconds'
71
+ to = params[:to_value].to_i.public_send(params[:to_unit].to_sym).ago
68
72
  (from..to)
69
73
  end
70
74
 
75
+ def n_intervals_seconds(range, intervals_count: 30)
76
+ start_time = range.begin
77
+ end_time = range.end
78
+ time_range_in_seconds = (end_time - start_time).to_i
79
+ (time_range_in_seconds / intervals_count.to_f).round
80
+ end
81
+
71
82
  def aggregate(items, range, intervals_count: 20)
72
83
  start_time = range.begin
73
84
  end_time = range.end
@@ -1,4 +1,33 @@
1
1
  module SolidApm
2
2
  module ApplicationHelper
3
+ def area_chart_options
4
+ {
5
+ module: true,
6
+ chart: {
7
+ type: 'area', height: '200', background: '0', foreColor: '#ffffff55', zoom: {
8
+ enabled: false,
9
+ }, toolbar: {
10
+ show: false,
11
+ }
12
+ },
13
+ xaxis: {
14
+ type: 'datetime',
15
+ tooltip: {
16
+ enabled: false
17
+
18
+ }
19
+ },
20
+ stroke: {
21
+ curve: 'smooth'
22
+ }, theme: {
23
+ mode: 'dark',
24
+ }, grid: {
25
+ show: true, borderColor: '#ffffff55',
26
+ }, dataLabels: {
27
+ enabled: false
28
+ },
29
+ tooltip: {x: {formatter: {function: {args: "val", body: "return new Date(val).toLocaleString()"}} }}
30
+ }
31
+ end
3
32
  end
4
33
  end
@@ -8,13 +8,14 @@ module SolidApm
8
8
  super do |name, start, finish, id, payload|
9
9
  transaction = SpanSubscriber::Base.transaction
10
10
  transaction.name = "#{payload[:request].controller_class}##{payload[:request].path_parameters[:action]}"
11
+ transaction.timestamp = start
11
12
  transaction.end_time = finish
12
- transaction.duration = ((transaction.end_time.to_f - transaction.timestamp.to_f) * 1000).round(6)
13
+ transaction.duration = ((finish.to_f - start.to_f) * 1000).round(6)
13
14
  transaction.metadata = {
14
15
  params: payload[:request].params.except(:controller, :action),
15
16
  context: SpanSubscriber::Base.context
16
17
  }
17
- SpanSubscriber::Base.context = nil
18
+ SpanSubscriber::Base.context = {}
18
19
  end
19
20
  end
20
21
 
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
  module SolidApm
3
- module SpanSubscriber
4
- class ActiveRecordSql < Base
5
- PATTERN = "sql.active_record"
3
+ module SpanSubscriber
4
+ class ActiveRecordSql < Base
5
+ PATTERN = "sql.active_record"
6
6
 
7
- def summary(payload)
8
- payload[:sql]
7
+ def summary(payload)
8
+ payload[:sql]
9
+ end
9
10
  end
10
11
  end
11
12
  end
12
- end
@@ -5,18 +5,23 @@
5
5
  <%= csrf_meta_tags %>
6
6
  <%= csp_meta_tag %>
7
7
 
8
- <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/apexcharts@4.4.0"></script>
9
9
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.1/css/bulma.min.css">
10
10
  <%= stylesheet_link_tag "solid_apm/application", media: "all" %>
11
11
  <%= javascript_include_tag "solid_apm/application", "data-turoblinks-track": "reload", type: "module" %>
12
- <%= javascript_include_tag "solid_apm/controllers/transaction-chart_controller", "data-turoblinks-track": "reload", type: "module" %>
13
- <%= javascript_include_tag "solid_apm/controllers/spans-chart_controller", "data-turoblinks-track": "reload", type: "module" %>
14
12
  </head>
15
13
 
16
- <body style="overflow: scroll">
14
+ <body>
17
15
  <section class="section">
18
16
  <%= yield %>
19
17
  </section>
18
+
19
+ <% if flash[:error] %>
20
+ <div class="notification is-danger mb-1" style="width: 20em; position: absolute; bottom: 1em; right: 1em;">
21
+ <button class="delete"></button>
22
+ <%= flash[:error] %>
23
+ </div>
24
+ <% end %>
20
25
  </body>
21
26
 
22
27
  </html>
@@ -0,0 +1,34 @@
1
+ <%= form_with path: transactions_path, method: :get do |f| %>
2
+ <div class="is-flex is-flex-direction-row is-justify-content-center is-align-items-center" style="gap: 1em">
3
+ <%= f.number_field :from_value, value: params[:from_value] || 60, min: 1, class: 'input', style: 'width: 6em' %>
4
+ <div class="select">
5
+ <%= f.select :from_unit, {
6
+ "minutes" => "minutes",
7
+ "hours" => "hours",
8
+ "days" => "days",
9
+ "weeks" => "weeks",
10
+ "months" => "months",
11
+ "years" => "years"
12
+ }, {selected: params[:from_unit] || 'minutes' } %>
13
+ </div>
14
+ <b>→</b>
15
+ <%= f.number_field :to_value, value: params[:to_value] || 1, min: 1, class: 'input', style: 'width: 6em' %>
16
+ <div class="select">
17
+ <%= f.select :to_unit, {
18
+ "seconds" => "seconds",
19
+ "minutes" => "minutes",
20
+ "hours" => "hours",
21
+ "days" => "days",
22
+ "weeks" => "weeks",
23
+ "months" => "months",
24
+ "years" => "years"
25
+ }, {selected: params[:to_unit] || 'seconds' } %>
26
+ </div>
27
+
28
+ <% if params[:name] %>
29
+ <%= f.hidden_field :name, value: params[:name] %>
30
+ <% end %>
31
+
32
+ <%= f.submit 'Apply', class: 'button' %>
33
+ </div>
34
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <div class="columns pt-2" style="height: 16em">
2
+ <div class="column">
3
+ <h2 class="ml-4">Throughput</h2>
4
+ <%= area_chart({ name: 'tmp', data: @throughput_data }, area_chart_options.merge(colors: ['#43BCCD'])) %>
5
+ </div>
6
+ <div class="column">
7
+ <h2 class="ml-4">Latency</h2>
8
+ <%= area_chart({ name: 'ms', data: @latency_data }, area_chart_options.merge(colors: ['#13d8aa'])) %>
9
+ </div>
10
+ </div>
@@ -1,26 +1,15 @@
1
- <h1 class="title">Transactions</h1>
2
-
3
- <%= form_with path: transactions_path, method: :get do |f| %>
4
- <div class="is-flex is-flex-direction-row is-justify-content-center is-align-items-center" style="gap: 1em">
5
- <%= f.label 'From' %>
6
- <%= f.number_field :from_value, value: params[:from_value] || 60, min: 1, class: 'input', style: 'width: 6em' %>
7
- <div class="select">
8
- <%= f.select :from_unit, {
9
- "minutes" => "minutes",
10
- "hours" => "hours",
11
- "days" => "days",
12
- "weeks" => "weeks",
13
- "months" => "months",
14
- "years" => "years"
15
- }, {selected: params[:from_unit] || 'minutes' } %>
16
- </div>
17
- <span class="has-text-white-ter">ago</span>
18
- <b>→</b>
19
- <span class="has-text-white-ter">now</span>
20
- <%= f.submit 'Apply', class: 'button' %>
21
- </div>
1
+ <% if params[:name] %>
2
+ <h1 class="title"><%= link_to '⬅ ', transactions_path(
3
+ from_value: params[:from_value],
4
+ from_unit: params[:from_unit],
5
+ to_value: params[:to_value],
6
+ to_unit: params[:to_unit]) %><%= params[:name] %></h1>
7
+ <% else %>
8
+ <h1 class="title">Solid APM</h1>
22
9
  <% end %>
23
- <div data-controller="transaction-chart"></div>
10
+
11
+ <%= render 'time_range_form' %>
12
+ <%= render 'charts' %>
24
13
 
25
14
  <table class="table is-fullwidth">
26
15
  <thead>
@@ -35,7 +24,12 @@
35
24
 
36
25
  <% @aggregated_transactions.each do |name, aggregation| %>
37
26
  <tr>
38
- <td><%= link_to name, transaction_by_name_path(name) %></td>
27
+ <td><%= link_to name, transactions_path(
28
+ from_value: params[:from_value],
29
+ from_unit: params[:from_unit],
30
+ to_value: params[:to_value],
31
+ to_unit: params[:to_unit],
32
+ name: name) %>
39
33
  <td><%= aggregation.latency.round(2) %> ms</td>
40
34
  <td><%= aggregation.tmp.round(2) %></td>
41
35
  <td><%= aggregation.percentile_95.round(2) %> ms</td>
@@ -45,3 +39,28 @@
45
39
  </tr>
46
40
  <% end %>
47
41
  </table>
42
+
43
+ <% if params[:name] %>
44
+ <table class="table is-fullwidth is-hoverable">
45
+ <thead>
46
+ <tr>
47
+ <th scope="col">Name</th>
48
+ <th scope="col">Timestamp</th>
49
+ <th scope="col">Type</th>
50
+ <th scope="col">Duration</th>
51
+ <th scope="col">Metadata</th>
52
+ </tr>
53
+ </thead>
54
+ <tbody>
55
+ <% @transactions_scope.order(timestamp: :desc).each do |transaction| %>
56
+ <tr>
57
+ <td><%= link_to transaction.name, transaction_spans_path(uuid: transaction.uuid) %></td>
58
+ <td><%= transaction.timestamp %></td>
59
+ <td><%= transaction.type %></td>
60
+ <td><%= transaction.duration.round(2) %></td>
61
+ <td><%= transaction.metadata %></td>
62
+ </tr>
63
+ <% end %>
64
+ </tbody>
65
+ </table>
66
+ <% end %>
@@ -0,0 +1,34 @@
1
+ <h1 class="title"><%= link_to '⬅ ', request.referer %><%= @transaction.name %></h1>
2
+ <h2 class="title is-6"><span class="has-text-grey">Trace ID:</span> <%= @transaction.uuid %></h2>
3
+ <h2 class="title is-6"><span class="has-text-grey">Timestamp:</span> <%= @transaction.timestamp %></h2>
4
+ <h2 class="title is-6"><span class="has-text-grey">Duration:</span> <%= @transaction.duration.round(2) %> ms</h2>
5
+ <h2 class="title is-6"><span class="has-text-grey">Metadata:</span> <%= @transaction.metadata %></h2>
6
+
7
+ <h2 class="title is-4 mt-6">Spans</h2>
8
+
9
+ <% min_start_time = @transaction.spans.minimum(:timestamp) %>
10
+ <% max_end_time = @transaction.spans.maximum(:end_time) %>
11
+ <% total_duration = max_end_time - min_start_time %>
12
+
13
+ <div class="is-fullwidth">
14
+ <% @transaction.spans.each do |span| %>
15
+ <% left_percent = ((span.timestamp - min_start_time).to_f / total_duration * 100) %>
16
+ <% width_percent = [((span.end_time - span.timestamp).to_f / total_duration * 100), 0.1].max %>
17
+ <% right_percent = (100 - left_percent - width_percent) %>
18
+
19
+ <div style="display: flex; height: 1.5em;">
20
+ <div style="flex: <%= left_percent %>"></div>
21
+ <div style="flex: <%= width_percent %>; display: flex; align-items: center; justify-content: center; border-radius: 5px" class="has-background-primary-15">
22
+ </div>
23
+ <div style="flex: <%= right_percent %>;"></div>
24
+ </div>
25
+ <div style="margin-left: <%= left_percent %>%" class="mt-1 mb-2">
26
+ <p>
27
+ <span class="has-text-grey-lighter "><%= span.name %></span><span class="has-text-grey pl-2"><%= span.duration.round(2) %>ms</span>
28
+ </p>
29
+ <p>
30
+ <%= span.summary %>
31
+ </p>
32
+ </div>
33
+ <% end %>
34
+ </div>
data/config/routes.rb CHANGED
@@ -2,10 +2,5 @@ SolidApm::Engine.routes.draw do
2
2
  root 'transactions#index'
3
3
 
4
4
  get 'transactions', to: 'transactions#index'
5
- get 'transactions/count_time_aggregations',
6
- default: { format: 'json' }
7
-
8
- get 'transactions/:id', to: 'transactions#show', as: 'transaction', constraints: { id: /\d+/ }
9
- get 'transactions/:name', to: 'transactions#show_by_name', as: 'transaction_by_name'
10
- get 'transactions/:id/spans', to: 'transactions#spans', as: 'transaction_spans'
5
+ get 'transactions/:uuid/spans', to: 'transactions#spans', as: 'transaction_spans'
11
6
  end
@@ -43,7 +43,6 @@ module SolidApm
43
43
  now = Time.zone.now
44
44
  SpanSubscriber::Base.transaction = Transaction.new(
45
45
  uuid: SecureRandom.uuid,
46
- timestamp: now,
47
46
  unix_minute: (now.to_f / 60).to_i,
48
47
  type: 'request'
49
48
  )
@@ -1,3 +1,3 @@
1
1
  module SolidApm
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
data/lib/solid_apm.rb CHANGED
@@ -1,3 +1,8 @@
1
+ require 'English' # For apexcharts Regex
2
+ require 'groupdate'
3
+ require 'active_median'
4
+ require 'apexcharts'
5
+
1
6
  require "solid_apm/version"
2
7
  require "solid_apm/engine"
3
8
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solid_apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean-Francis Bastien
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-01-17 00:00:00.000000000 Z
10
+ date: 2025-02-12 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: actionpack
@@ -65,6 +65,48 @@ dependencies:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '7.1'
68
+ - !ruby/object:Gem::Dependency
69
+ name: apexcharts
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: groupdate
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: active_median
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
68
110
  description: SolidApm allow you to monitor your application without any external service.
69
111
  email:
70
112
  - bhacaz@gmail.com
@@ -77,8 +119,6 @@ files:
77
119
  - Rakefile
78
120
  - app/assets/config/solid_apm_manifest.js
79
121
  - app/assets/javascripts/solid_apm/application.js
80
- - app/assets/javascripts/solid_apm/controllers/spans-chart_controller.js
81
- - app/assets/javascripts/solid_apm/controllers/transaction-chart_controller.js
82
122
  - app/assets/stylesheets/solid_apm/application.css
83
123
  - app/controllers/solid_apm/application_controller.rb
84
124
  - app/controllers/solid_apm/transactions_controller.rb
@@ -95,10 +135,11 @@ files:
95
135
  - app/models/solid_apm/transaction.rb
96
136
  - app/views/javascripts/_javascripts.html.erb
97
137
  - app/views/layouts/solid_apm/application.html.erb
138
+ - app/views/solid_apm/application/_time_range_form.html.erb
98
139
  - app/views/solid_apm/spans/index.html.erb
140
+ - app/views/solid_apm/transactions/_charts.html.erb
99
141
  - app/views/solid_apm/transactions/index.html.erb
100
- - app/views/solid_apm/transactions/show.html.erb
101
- - app/views/solid_apm/transactions/show_by_name.html.erb
142
+ - app/views/solid_apm/transactions/spans.html.erb
102
143
  - config/routes.rb
103
144
  - db/migrate/20240608015633_create_solid_apm_transactions.rb
104
145
  - db/migrate/20240608021940_create_solid_apm_spans.rb
@@ -1,97 +0,0 @@
1
- import {
2
- Controller,
3
- } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.js";
4
-
5
- // Connects to data-controller="spans-charts"
6
- window.Stimulus.register('spans-chart',
7
- class extends Controller {
8
- static values = { id: String }
9
-
10
- connect() {
11
- console.log("Connected")
12
- const options = {
13
- series: [
14
- {
15
- data: []
16
- }
17
- ],
18
- chart: {
19
- type: "rangeBar",
20
- height: "250em",
21
- },
22
- plotOptions: {
23
- bar: {
24
- horizontal: true
25
- }
26
- },
27
- xaxis: {
28
- type: "datetime",
29
- labels: {
30
- show: false
31
- }
32
- },
33
- tooltip: {
34
- custom: function ({y1, y2,dataPointIndex, seriesIndex, w}) {
35
- // custom: function (opts) {
36
- // console.log(opts)
37
- // console.log(value)
38
- return (
39
- '<div class="apexcharts-tooltip-title has-text-black" style="max-width: 40em; text-wrap: balance;">' +
40
- w.globals.initialSeries[seriesIndex].data[dataPointIndex].duration + "ms" +
41
- "<br>" +
42
- w.globals.initialSeries[seriesIndex].data[dataPointIndex].name +
43
- "<br>" +
44
- w.globals.initialSeries[seriesIndex].data[dataPointIndex].summary +
45
- '</div>'
46
- )
47
- }
48
- },
49
- yaxis: {
50
- labels: {
51
- formatter: function (value, opts) {
52
- if (opts === undefined) {
53
- return value[1] - value[0] + "ms"
54
- }
55
- if (opts.dataPointIndex >= 0) {
56
- return opts.w.globals.initialSeries[opts.seriesIndex].data[opts.dataPointIndex].name
57
- }
58
- return value
59
- }
60
- }
61
- },
62
- }
63
-
64
- fetch(this.idValue + "/spans.json")
65
- .then(response => response.json())
66
- .then(data => {
67
- options.series[0].data = data.map(d => {
68
- let startTime = new Date(d.timestamp).getTime()
69
- let endTime = new Date(d.end_time).getTime()
70
- if (endTime - startTime < 1) {
71
- endTime = startTime + 1
72
- }
73
- return {
74
- x: d.uuid,
75
- y: [startTime, endTime],
76
- name: d.name,
77
- summary: d.summary || d.name,
78
- duration: this.round(d.duration, 2)
79
- }
80
- })
81
- this.chart = new ApexCharts(this.element, options)
82
- this.chart.render()
83
- })
84
- }
85
-
86
- disconnect() {
87
- if (this.chart) {
88
- this.chart.destroy()
89
- this.chart = null
90
- }
91
- }
92
-
93
- round(num, decimalPlaces = 0) {
94
- num = Math.round(num + "e" + decimalPlaces);
95
- return Number(num + "e" + -decimalPlaces);
96
- }
97
- })
@@ -1,76 +0,0 @@
1
- import {
2
- Controller,
3
- } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.js";
4
- // unload chart https://github.com/Deanout/weight_tracker/blob/d4123acb952d91fcc9bedb96bbd786088a71482a/app/javascript/controllers/weights_controller.js#L4
5
- // tooltip: {
6
- // y: {
7
- // formatter: function (value, {series, seriesIndex, dataPointIndex, w}) {
8
- // return w.globals.initialSeries[seriesIndex].data[dataPointIndex].name + "\n" + value + "ms"
9
- // }
10
- // }
11
- // }
12
-
13
- // Connects to data-controller="transaction-chart"
14
- window.Stimulus.register('transaction-chart',
15
- class extends Controller {
16
- static values = { name: String }
17
-
18
- connect() {
19
- var options = {
20
- chart: {
21
- type: 'bar',
22
- height: '200em'
23
- },
24
- series: [{
25
- name: 'tpm',
26
- }],
27
- xaxis: {
28
- type: 'datetime'
29
- },
30
- dataLabels: {
31
- enabled: false
32
- },
33
- tooltip: {
34
- x: {
35
- formatter: function (value) {
36
- return new Date(value).toLocaleString()
37
- }
38
- }
39
- }
40
- }
41
-
42
- let path = "count_time_aggregations?";
43
- if (this.nameValue) {
44
- path = path + "name=" + encodeURIComponent(this.nameValue);
45
- }
46
-
47
- const fromValue = document.querySelector('input[name="from_value"]')
48
- const fromUnit = document.querySelector('select[name="from_unit"]');
49
- if (fromValue && fromUnit) {
50
- path = path + "&from_value=" + fromValue.value + "&from_unit=" + fromUnit.value;
51
- }
52
-
53
- const base = window.location.pathname.split('/transactions')[0];
54
- path = base + "/transactions/" + path;
55
- path = path.replace("//", "/");
56
- fetch(path)
57
- .then(response => response.json())
58
- .then(data => {
59
- const transformedData = []
60
- for (let [key, value] of Object.entries(data)) {
61
- transformedData.push({x: key, y: value})
62
- }
63
- options.series[0].data = transformedData
64
- this.chart = new ApexCharts(this.element, options)
65
- this.chart.render()
66
- })
67
- }
68
-
69
- // Unloads the chart before loading new data.
70
- disconnect() {
71
- if (this.chart) {
72
- this.chart.destroy();
73
- this.chart = null;
74
- }
75
- }
76
- })
@@ -1,9 +0,0 @@
1
-
2
- <h1 class="title"><%= @transaction.name %></h1>
3
- <h2 class="title is-6"><span class="has-text-grey-dark">Trace ID:</span> <%= @transaction.uuid %></h2>
4
- <h2 class="title is-6"><span class="has-text-grey-dark">Timestamp:</span> <%= @transaction.timestamp %></h2>
5
- <h2 class="title is-6"><span class="has-text-grey-dark">Duration:</span> <%= @transaction.duration %> ms</h2>
6
- <h2 class="title is-6"><span class="has-text-grey-dark">Unix minute:</span> <%= @transaction.unix_minute %></h2>
7
- <h2 class="title is-6"><span class="has-text-grey-dark">Metadata:</span> <%= @transaction.metadata %></h2>
8
-
9
- <%= render template: 'solid_apm/spans/index', collection: @transaction.spans, locals: { spans: @transaction.spans } %>
@@ -1,27 +0,0 @@
1
- <h1 class="title is-3"><%= params[:name] %></h1>
2
- <div data-controller="transaction-chart" data-transaction-chart-name-value="<%= params[:name] %>"></div>
3
-
4
- <table class="table">
5
- <thead>
6
- <tr>
7
- <% SolidApm::Transaction.attribute_names.each do |attribute| %>
8
- <% next if attribute.to_s.end_with?('_at') %>
9
- <th scope="col"><%= attribute.humanize %></th>
10
- <% end %>
11
- </tr>
12
- </thead>
13
- <tbody>
14
- <% @transactions.each do |transaction| %>
15
- <tr>
16
- <% transaction.attributes.each do |attribute| %>
17
- <% next if attribute[0].to_s.end_with?('_at') %>
18
- <% if attribute[0] == 'uuid' %>
19
- <td><%= link_to attribute[1], transaction_path(transaction) %></td>
20
- <% else %>
21
- <td><%= attribute[1] %></td>
22
- <% end %>
23
- <% end %>
24
- </tr>
25
- <% end %>
26
- </tbody>
27
- </table>