signalman 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +8 -0
- data/app/assets/config/signalman_manifest.js +0 -0
- data/app/controllers/signalman/application_controller.rb +4 -0
- data/app/controllers/signalman/generators/models_controller.rb +15 -0
- data/app/controllers/signalman/generators/scaffolds_controller.rb +15 -0
- data/app/controllers/signalman/jobs_controller.rb +11 -0
- data/app/controllers/signalman/mails_controller.rb +11 -0
- data/app/controllers/signalman/queries_controller.rb +11 -0
- data/app/controllers/signalman/requests_controller.rb +11 -0
- data/app/controllers/signalman/views_controller.rb +11 -0
- data/app/helpers/signalman/events_helper.rb +18 -0
- data/app/models/signalman/event.rb +25 -0
- data/app/models/signalman.rb +5 -0
- data/app/views/layouts/signalman/application.html.erb +22 -0
- data/app/views/signalman/generators/models/create.html.erb +5 -0
- data/app/views/signalman/generators/models/show.html.erb +36 -0
- data/app/views/signalman/generators/scaffolds/create.html.erb +9 -0
- data/app/views/signalman/generators/scaffolds/show.html.erb +36 -0
- data/app/views/signalman/jobs/index.html.erb +28 -0
- data/app/views/signalman/jobs/show.html.erb +17 -0
- data/app/views/signalman/mails/index.html.erb +28 -0
- data/app/views/signalman/mails/show.html.erb +17 -0
- data/app/views/signalman/queries/index.html.erb +24 -0
- data/app/views/signalman/queries/show.html.erb +17 -0
- data/app/views/signalman/requests/index.html.erb +31 -0
- data/app/views/signalman/requests/show.html.erb +19 -0
- data/app/views/signalman/shared/_flash.html.erb +7 -0
- data/app/views/signalman/shared/_nav.html.erb +30 -0
- data/app/views/signalman/views/index.html.erb +27 -0
- data/app/views/signalman/views/show.html.erb +20 -0
- data/config/routes.rb +16 -0
- data/db/migrate/20230729122215_create_signalman_events.rb +15 -0
- data/lib/signalman/engine.rb +16 -0
- data/lib/signalman/version.rb +3 -0
- data/lib/signalman.rb +183 -0
- data/lib/tasks/signalman_tasks.rake +4 -0
- metadata +98 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: b339dda80c8dea8c1ce6c651d543c808fdcacc634b013d27e3791fe9be6c1a13
         | 
| 4 | 
            +
              data.tar.gz: 482987c4c114ee1e1f3c630c45e37879dc058b70747712e82b5f818da28fe129
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 9c998b4967fd840aa5c503fc4aa9242ea6e479300b96bab94d6720ab8fadb2c7630d967deed07f6a6360a3237371a6d58df52ab612366b3ac32c90bd57a1ae4d
         | 
| 7 | 
            +
              data.tar.gz: 8c17c1381bbf37112493f7cf9afe13322951c2089f9d71b9e5bdd000eab4c843cc3dc19a085d6ce8aac103ef93127e8357c2834dbb5a8932065c612d01fcf29c
         | 
    
        data/MIT-LICENSE
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            Copyright 2023 Chris Oliver
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 5 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 6 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 7 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 | 
            +
            the following conditions:
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 12 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 17 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 18 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 19 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 20 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            # Signalman
         | 
| 2 | 
            +
            Short description and motivation.
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            ## Usage
         | 
| 5 | 
            +
            How to use my plugin.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ## Installation
         | 
| 8 | 
            +
            Add this line to your application's Gemfile:
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ```ruby
         | 
| 11 | 
            +
            gem "signalman"
         | 
| 12 | 
            +
            ```
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            And then execute:
         | 
| 15 | 
            +
            ```bash
         | 
| 16 | 
            +
            $ bundle
         | 
| 17 | 
            +
            ```
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            Or install it yourself as:
         | 
| 20 | 
            +
            ```bash
         | 
| 21 | 
            +
            $ gem install signalman
         | 
| 22 | 
            +
            ```
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            ## Contributing
         | 
| 25 | 
            +
            Contribution directions go here.
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            ## License
         | 
| 28 | 
            +
            The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
         | 
    
        data/Rakefile
    ADDED
    
    
| 
            File without changes
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            require "open3"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Signalman
         | 
| 4 | 
            +
              class Generators::ModelsController < ApplicationController
         | 
| 5 | 
            +
                def show
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def create
         | 
| 9 | 
            +
                  @fields = params[:fields].map{ |field| [field[:name], field[:type]].join(":") }
         | 
| 10 | 
            +
                  Bundler.with_original_env do
         | 
| 11 | 
            +
                    @stdout, @stderr, @status = Open3.capture3("rails", "generate", "model", params[:model_name], *@fields)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            require "open3"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Signalman
         | 
| 4 | 
            +
              class Generators::ScaffoldsController < ApplicationController
         | 
| 5 | 
            +
                def show
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def create
         | 
| 9 | 
            +
                  @fields = params[:fields].map{ |field| [field[:name], field[:type]].join(":") }
         | 
| 10 | 
            +
                  Bundler.with_original_env do
         | 
| 11 | 
            +
                    @stdout, @stderr, @status = Open3.capture3("rails", "generate", "scaffold", params[:model_name], *@fields)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            module Signalman
         | 
| 2 | 
            +
              module EventsHelper
         | 
| 3 | 
            +
                def signalman_path_for(event)
         | 
| 4 | 
            +
                  block = Signalman.events.find{ |key, _| key.match? event.name }.last[:path]
         | 
| 5 | 
            +
                  instance_exec event, &block
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def badge_for_request_duration(duration, &block)
         | 
| 9 | 
            +
                  if duration <= 200
         | 
| 10 | 
            +
                    tag.span "#{duration.round}ms", class: "bg-gray-100 text-gray-800 px-2 py-1 rounded text-xs"
         | 
| 11 | 
            +
                  elsif duration <= 500
         | 
| 12 | 
            +
                    tag.span "#{duration.round}ms", class: "bg-yellow-100 text-yellow-800 px-2 py-1 rounded text-xs"
         | 
| 13 | 
            +
                  else
         | 
| 14 | 
            +
                    tag.span "#{duration.round}ms", class: "bg-red-100 text-red-800 rounded px-2 py-1 text-xs"
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            class Signalman::Event < ApplicationRecord
         | 
| 2 | 
            +
              scope :requests, ->{ where(name: "process_action.action_controller") }
         | 
| 3 | 
            +
              scope :mails, ->{ where(name: "deliver.action_mailer") }
         | 
| 4 | 
            +
              scope :queries, ->{ where(name: "sql.active_record") }
         | 
| 5 | 
            +
              scope :views, ->{
         | 
| 6 | 
            +
                where(name: [
         | 
| 7 | 
            +
                  "render_template.action_view",
         | 
| 8 | 
            +
                  "render_partial.action_view",
         | 
| 9 | 
            +
                  "render_collection.action_view",
         | 
| 10 | 
            +
                  "render_layout.action_view",
         | 
| 11 | 
            +
                ])
         | 
| 12 | 
            +
              }
         | 
| 13 | 
            +
              scope :jobs, -> {
         | 
| 14 | 
            +
                where(name: [
         | 
| 15 | 
            +
                  "enqueue_at.active_job",
         | 
| 16 | 
            +
                  "enqueue.active_job",
         | 
| 17 | 
            +
                  "perform.active_job",
         | 
| 18 | 
            +
                  "perform_start.active_job",
         | 
| 19 | 
            +
                  "discard.active_job",
         | 
| 20 | 
            +
                ])
         | 
| 21 | 
            +
              }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
             | 
| 24 | 
            +
              scope :recent_first, ->{ order(created_at: :desc) }
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            <!DOCTYPE html>
         | 
| 2 | 
            +
            <html>
         | 
| 3 | 
            +
              <head>
         | 
| 4 | 
            +
                <title>Signalman</title>
         | 
| 5 | 
            +
                <meta name="viewport" content="width=device-width,initial-scale=1">
         | 
| 6 | 
            +
                <%= csrf_meta_tags %>
         | 
| 7 | 
            +
                <%= csp_meta_tag %>
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                <script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio"></script>
         | 
| 10 | 
            +
              </head>
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              <body>
         | 
| 13 | 
            +
                <div class="flex gap-4">
         | 
| 14 | 
            +
                  <%= render "signalman/shared/nav" %>
         | 
| 15 | 
            +
                  <div class="ml-72 w-full p-4 sm:p-8 prose max-w-none prose-a:no-underline">
         | 
| 16 | 
            +
                    <%= render "signalman/shared/flash" %>
         | 
| 17 | 
            +
                    <%= yield %>
         | 
| 18 | 
            +
                  </div>
         | 
| 19 | 
            +
                </div>
         | 
| 20 | 
            +
              </body>
         | 
| 21 | 
            +
            </html>
         | 
| 22 | 
            +
             | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            <h1>Generate Model </h1>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <%= form_with url: generators_model_path do |form| %>
         | 
| 4 | 
            +
              <div>
         | 
| 5 | 
            +
                <%= form.label :model_name, class: "block" %>
         | 
| 6 | 
            +
                <%= form.text_field :model_name, placeholder: "User", required: true %>
         | 
| 7 | 
            +
              </div>
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              <template id="field">
         | 
| 10 | 
            +
                <div class="mt-4">
         | 
| 11 | 
            +
                  <%= form.text_field "fields[][name]", placeholder: "email", required: true %>
         | 
| 12 | 
            +
                  <%= form.select "fields[][type]", options_for_select(ActiveRecord::Base.connection.class::NATIVE_DATABASE_TYPES.keys.excluding(:primary_key)) %>
         | 
| 13 | 
            +
                  <%= button_tag "Remove", onclick: "event.preventDefault(); this.parentElement.remove()" %>
         | 
| 14 | 
            +
                </div>
         | 
| 15 | 
            +
              </template>
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              <label>Fields</label>
         | 
| 18 | 
            +
              <div id="fields">
         | 
| 19 | 
            +
              </div>
         | 
| 20 | 
            +
              <%= button_tag "Add field", onclick: "addField(event)" %>
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              <div class="mt-4">
         | 
| 23 | 
            +
                <%= form.button "Generate" %>
         | 
| 24 | 
            +
              </div>
         | 
| 25 | 
            +
            <% end %>
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            <script>
         | 
| 28 | 
            +
              const template = document.querySelector("#field")
         | 
| 29 | 
            +
              const fields = document.querySelector("#fields")
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              function addField(event) {
         | 
| 32 | 
            +
                event.preventDefault()
         | 
| 33 | 
            +
                const clone = template.content.cloneNode(true)
         | 
| 34 | 
            +
                fields.appendChild(clone)
         | 
| 35 | 
            +
              }
         | 
| 36 | 
            +
            </script>
         | 
| @@ -0,0 +1,9 @@ | |
| 1 | 
            +
            <% if @status.success? %>
         | 
| 2 | 
            +
              <p>Visit <%= link_to "/#{params[:model_name].underscore.pluralize}", "/#{params[:model_name].underscore.pluralize}", target: :_blank %></p>
         | 
| 3 | 
            +
            <% end %>
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            <pre>
         | 
| 6 | 
            +
            $ rails generate scaffold <%= params[:model_name] %> <%= @fields.join(" ") %>
         | 
| 7 | 
            +
            <%= simple_format @stdout %>
         | 
| 8 | 
            +
            <%= simple_format @stderr %>
         | 
| 9 | 
            +
            </pre>
         | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            <h1>Generate Scaffold</h1>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <%= form_with url: generators_scaffold_path do |form| %>
         | 
| 4 | 
            +
              <div>
         | 
| 5 | 
            +
                <%= form.label :model_name, class: "block" %>
         | 
| 6 | 
            +
                <%= form.text_field :model_name, placeholder: "User", required: true %>
         | 
| 7 | 
            +
              </div>
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              <template id="field">
         | 
| 10 | 
            +
                <div class="mt-4">
         | 
| 11 | 
            +
                  <%= form.text_field "fields[][name]", placeholder: "email", required: true %>
         | 
| 12 | 
            +
                  <%= form.select "fields[][type]", options_for_select(ActiveRecord::Base.connection.class::NATIVE_DATABASE_TYPES.keys.excluding(:primary_key)) %>
         | 
| 13 | 
            +
                  <%= button_tag "Remove", onclick: "event.preventDefault(); this.parentElement.remove()" %>
         | 
| 14 | 
            +
                </div>
         | 
| 15 | 
            +
              </template>
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              <label>Fields</label>
         | 
| 18 | 
            +
              <div id="fields">
         | 
| 19 | 
            +
              </div>
         | 
| 20 | 
            +
              <%= button_tag "Add field", onclick: "addField(event)" %>
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              <div class="mt-4">
         | 
| 23 | 
            +
                <%= form.button "Generate" %>
         | 
| 24 | 
            +
              </div>
         | 
| 25 | 
            +
            <% end %>
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            <script>
         | 
| 28 | 
            +
              const template = document.querySelector("#field")
         | 
| 29 | 
            +
              const fields = document.querySelector("#fields")
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              function addField(event) {
         | 
| 32 | 
            +
                event.preventDefault()
         | 
| 33 | 
            +
                const clone = template.content.cloneNode(true)
         | 
| 34 | 
            +
                fields.appendChild(clone)
         | 
| 35 | 
            +
              }
         | 
| 36 | 
            +
            </script>
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            <h1>Jobs</h1>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <div class="table w-full">
         | 
| 4 | 
            +
              <div class="table-header-group">
         | 
| 5 | 
            +
                <div class="table-row font-bold">
         | 
| 6 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Job</div>
         | 
| 7 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Id</div>
         | 
| 8 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Arguments</div>
         | 
| 9 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Duration</div>
         | 
| 10 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Happened</div>
         | 
| 11 | 
            +
                </div>
         | 
| 12 | 
            +
              </div>
         | 
| 13 | 
            +
              <div class="table-row-group">
         | 
| 14 | 
            +
                <% @events.each do |event| %>
         | 
| 15 | 
            +
                  <%= link_to signalman_path_for(event), class: "table-row", id: dom_id(event) do %>
         | 
| 16 | 
            +
                    <%= tag.div event.payload["class"], class: "table-cell border-b border-neutral-100 p-2" %>
         | 
| 17 | 
            +
                    <%= tag.div event.payload["id"], class: "table-cell border-b border-neutral-100 p-2" %>
         | 
| 18 | 
            +
                    <%= tag.div event.payload["args"], class: "table-cell border-b border-neutral-100 p-2" %>
         | 
| 19 | 
            +
                    <%= tag.div class: "table-cell border-b border-neutral-100 p-2" do %>
         | 
| 20 | 
            +
                      <%= event.duration.round %>ms
         | 
| 21 | 
            +
                    <% end %>
         | 
| 22 | 
            +
                    <%= tag.div class: "table-cell border-b border-neutral-100 p-2" do %>
         | 
| 23 | 
            +
                      <%= time_ago_in_words event.started_at %>
         | 
| 24 | 
            +
                    <% end %>
         | 
| 25 | 
            +
                  <% end %>
         | 
| 26 | 
            +
                <% end %>
         | 
| 27 | 
            +
              </div>
         | 
| 28 | 
            +
            </div>
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            <h1 class="mb-2"><%= @event.payload["class"] %></h1>
         | 
| 2 | 
            +
            <div class="text-xs">Started at <%= @event.started_at %></div>
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            <h4>ID</h4>
         | 
| 5 | 
            +
            <pre><%= @event.payload["id"] %></pre>
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            <h4>Queue Name</h4>
         | 
| 8 | 
            +
            <pre><%= @event.payload["queue_name"] %></pre>
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            <h4>Enqueued At</h4>
         | 
| 11 | 
            +
            <pre><%= @event.payload["enqueued_at"] %></pre>
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            <h4>Scheduled At</h4>
         | 
| 14 | 
            +
            <pre><%= @event.payload["scheduled_at"] || "nil" %></pre>
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            <h4>Arguments</h4>
         | 
| 17 | 
            +
            <pre><%= @event.payload["args"] %></pre>
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            <h1>Mail</h1>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <div class="table w-full">
         | 
| 4 | 
            +
              <div class="table-header-group">
         | 
| 5 | 
            +
                <div class="table-row font-bold">
         | 
| 6 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Mailer</div>
         | 
| 7 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Subject</div>
         | 
| 8 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">To</div>
         | 
| 9 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Duration</div>
         | 
| 10 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Happened</div>
         | 
| 11 | 
            +
                </div>
         | 
| 12 | 
            +
              </div>
         | 
| 13 | 
            +
              <div class="table-row-group">
         | 
| 14 | 
            +
                <% @events.each do |event| %>
         | 
| 15 | 
            +
                  <%= link_to signalman_path_for(event), class: "table-row", id: dom_id(event) do %>
         | 
| 16 | 
            +
                    <%= tag.div event.payload["mailer"], class: "table-cell border-b border-neutral-100 p-2" %>
         | 
| 17 | 
            +
                    <%= tag.div event.payload["subject"], class: "table-cell border-b border-neutral-100 p-2" %>
         | 
| 18 | 
            +
                    <%= tag.div event.payload["to"], class: "table-cell border-b border-neutral-100 p-2" %>
         | 
| 19 | 
            +
                    <%= tag.div class: "table-cell border-b border-neutral-100 p-2" do %>
         | 
| 20 | 
            +
                      <%= event.duration.round %>ms
         | 
| 21 | 
            +
                    <% end %>
         | 
| 22 | 
            +
                    <%= tag.div class: "table-cell border-b border-neutral-100 p-2" do %>
         | 
| 23 | 
            +
                      <%= time_ago_in_words event.started_at %>
         | 
| 24 | 
            +
                    <% end %>
         | 
| 25 | 
            +
                  <% end %>
         | 
| 26 | 
            +
                <% end %>
         | 
| 27 | 
            +
              </div>
         | 
| 28 | 
            +
            </div>
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            <h1 class="mb-2"><%= @event.payload["mailer"] %></h1>
         | 
| 2 | 
            +
            <div class="text-xs">Started at <%= @event.started_at %></div>
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            <h4>Message ID</h4>
         | 
| 5 | 
            +
            <pre><%= @event.payload["message_id"] %></pre>
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            <h4>Subject</h4>
         | 
| 8 | 
            +
            <pre><%= @event.payload["subject"] %></pre>
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            <h4>To</h4>
         | 
| 11 | 
            +
            <pre><%= @event.payload["to"] %></pre>
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            <h4>From </h4>
         | 
| 14 | 
            +
            <pre><%= @event.payload["from"] %></pre>
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            <h4>Mail</h4>
         | 
| 17 | 
            +
            <pre><%= @event.payload["mail"] %></pre>
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            <h1>Queries</h1>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <div class="table w-full">
         | 
| 4 | 
            +
              <div class="table-header-group">
         | 
| 5 | 
            +
                <div class="table-row font-bold">
         | 
| 6 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">SQL</div>
         | 
| 7 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Duration</div>
         | 
| 8 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Happened</div>
         | 
| 9 | 
            +
                </div>
         | 
| 10 | 
            +
              </div>
         | 
| 11 | 
            +
              <div class="table-row-group">
         | 
| 12 | 
            +
                <% @events.each do |event| %>
         | 
| 13 | 
            +
                  <%= link_to signalman_path_for(event), class: "table-row", id: dom_id(event) do %>
         | 
| 14 | 
            +
                    <%= tag.div event.payload["sql"], class: "table-cell border-b border-neutral-100 p-2" %>
         | 
| 15 | 
            +
                    <%= tag.div class: "table-cell border-b border-neutral-100 p-2" do %>
         | 
| 16 | 
            +
                      <%= event.duration.round %>ms
         | 
| 17 | 
            +
                    <% end %>
         | 
| 18 | 
            +
                    <%= tag.div class: "table-cell border-b border-neutral-100 p-2" do %>
         | 
| 19 | 
            +
                      <%= time_ago_in_words event.started_at %>
         | 
| 20 | 
            +
                    <% end %>
         | 
| 21 | 
            +
                  <% end %>
         | 
| 22 | 
            +
                <% end %>
         | 
| 23 | 
            +
              </div>
         | 
| 24 | 
            +
            </div>
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            <h1 class="mb-2"><%= @event.payload["name"] %></h1>
         | 
| 2 | 
            +
            <div class="text-xs">Started at <%= @event.started_at %></div>
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            <h4>SQL</h4>
         | 
| 5 | 
            +
            <pre><%= @event.payload["sql"] %></pre>
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            <h4>Binds</h4>
         | 
| 8 | 
            +
            <pre><%= @event.payload["binds"] %></pre>
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            <h4>Type Casted Binds</h4>
         | 
| 11 | 
            +
            <pre><%= @event.payload["type_casted_binds"] %></pre>
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            <h4>Statement Name</h4>
         | 
| 14 | 
            +
            <pre><%= @event.payload["statement_name"] %></pre>
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            <h4>Async</h4>
         | 
| 17 | 
            +
            <pre><%= @event.payload["async"] %></pre>
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            <h1>Requests</h1>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <div class="table w-full">
         | 
| 4 | 
            +
              <div class="table-header-group">
         | 
| 5 | 
            +
                <div class="table-row font-bold">
         | 
| 6 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Method</div>
         | 
| 7 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Path</div>
         | 
| 8 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Status</div>
         | 
| 9 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Duration</div>
         | 
| 10 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Happened</div>
         | 
| 11 | 
            +
                </div>
         | 
| 12 | 
            +
              </div>
         | 
| 13 | 
            +
              <div class="table-row-group">
         | 
| 14 | 
            +
                <% @events.each do |event| %>
         | 
| 15 | 
            +
                  <%= link_to signalman_path_for(event), class: "table-row", id: dom_id(event) do %>
         | 
| 16 | 
            +
                    <%= tag.div event.payload["method"], class: "table-cell border-b border-neutral-100 p-2" %>
         | 
| 17 | 
            +
                    <%= tag.div event.payload["path"], class: "table-cell border-b border-neutral-100 p-2" %>
         | 
| 18 | 
            +
                    <%= tag.div class: "table-cell border-b border-neutral-100 p-2" do %>
         | 
| 19 | 
            +
                      <%= event.payload["status"] %>
         | 
| 20 | 
            +
                      <%= Rack::Utils::HTTP_STATUS_CODES[event.payload["status"]] %>
         | 
| 21 | 
            +
                    <% end %>
         | 
| 22 | 
            +
                    <%= tag.div class: "table-cell border-b border-neutral-100 p-2" do %>
         | 
| 23 | 
            +
                      <%= badge_for_request_duration(event.duration) %>
         | 
| 24 | 
            +
                    <% end %>
         | 
| 25 | 
            +
                    <%= tag.div class: "table-cell border-b border-neutral-100 p-2" do %>
         | 
| 26 | 
            +
                      <%= time_ago_in_words event.started_at %>
         | 
| 27 | 
            +
                    <% end %>
         | 
| 28 | 
            +
                  <% end %>
         | 
| 29 | 
            +
                <% end %>
         | 
| 30 | 
            +
              </div>
         | 
| 31 | 
            +
            </div>
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            <h1 class="mb-2"><%= @event.payload["method"] %> <%= @event.payload["path"] %> as <%= @event.payload["format"].upcase %></h1>
         | 
| 2 | 
            +
            <div class="text-xs">Started at <%= @event.started_at %></div>
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            <h4>Processed by</h4>
         | 
| 5 | 
            +
            <pre><%= @event.payload["controller"] %>#<%= @event.payload["action"] %></pre>
         | 
| 6 | 
            +
            <p class="text-sm">Completed in <%= @event.duration.round %>ms (Views: <%= @event.payload["view_runtime"].round %>ms | ActiveRecord: <%= @event.payload["db_runtime"].round %>ms)</p>
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            <h4>Response</h4>
         | 
| 9 | 
            +
            <pre><%= @event.payload["status"] %> <%= Rack::Utils::HTTP_STATUS_CODES[@event.payload["status"]] %></pre>
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            <h4>Params</h4>
         | 
| 12 | 
            +
            <pre><%= @event.payload["params"] %></pre>
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            <h4>Headers</h4>
         | 
| 15 | 
            +
            <pre>
         | 
| 16 | 
            +
            <% @event.payload["headers"].sort.each do |key, value| %>
         | 
| 17 | 
            +
            <%= key %>: <%= value %>
         | 
| 18 | 
            +
            <% end %>
         | 
| 19 | 
            +
            </pre>
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            <nav class="p-4 sm:p-8 fixed inset-y-0 w-72 bg-neutral-900 text-white">
         | 
| 2 | 
            +
              <h1 class="flex items-center gap-1 font-bold">
         | 
| 3 | 
            +
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6">
         | 
| 4 | 
            +
                  <path fill-rule="evenodd" d="M10.5 3.798v5.02a3 3 0 01-.879 2.121l-2.377 2.377a9.845 9.845 0 015.091 1.013 8.315 8.315 0 005.713.636l.285-.071-3.954-3.955a3 3 0 01-.879-2.121v-5.02a23.614 23.614 0 00-3 0zm4.5.138a.75.75 0 00.093-1.495A24.837 24.837 0 0012 2.25a25.048 25.048 0 00-3.093.191A.75.75 0 009 3.936v4.882a1.5 1.5 0 01-.44 1.06l-6.293 6.294c-1.62 1.621-.903 4.475 1.471 4.88 2.686.46 5.447.698 8.262.698 2.816 0 5.576-.239 8.262-.697 2.373-.406 3.092-3.26 1.47-4.881L15.44 9.879A1.5 1.5 0 0115 8.818V3.936z" clip-rule="evenodd" />
         | 
| 5 | 
            +
                </svg>
         | 
| 6 | 
            +
                <%= link_to "Signalman", root_path %>
         | 
| 7 | 
            +
              </h1>
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              <br />
         | 
| 10 | 
            +
              <%= link_to "Back to app", main_app.root_path, class: "block text-sm" %>
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              <br />
         | 
| 13 | 
            +
              <%= link_to "Requests", requests_path, class: "block" %>
         | 
| 14 | 
            +
              <%= link_to "Jobs", jobs_path, class: "block" %>
         | 
| 15 | 
            +
              <%= link_to "Mail", mails_path, class: "block" %>
         | 
| 16 | 
            +
              <%= link_to "Queries", queries_path, class: "block" %>
         | 
| 17 | 
            +
              <%= link_to "Views", views_path, class: "block" %>
         | 
| 18 | 
            +
              <%#= link_to "Cache", requests_path, class: "block" %>
         | 
| 19 | 
            +
              <%#= link_to "Exceptions", requests_path, class: "block" %>
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              <br/>
         | 
| 22 | 
            +
              <h2>Generators</h2>
         | 
| 23 | 
            +
              <%= link_to "Model", generators_model_path, class: "block" %>
         | 
| 24 | 
            +
              <%= link_to "Scaffold", generators_scaffold_path, class: "block" %>
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              <br/>
         | 
| 27 | 
            +
              <%= link_to "Routes", "/rails/info/routes", class: "block" %>
         | 
| 28 | 
            +
              <%= link_to "Mailer Previews", "/rails/mailers", class: "block" %>
         | 
| 29 | 
            +
              <%= link_to "Inbound Emails", "/rails/conductor/action_mailbox/inbound_emails", class: "block" %>
         | 
| 30 | 
            +
            </nav>
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            <h1>Views</h1>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <div class="table w-full">
         | 
| 4 | 
            +
              <div class="table-header-group">
         | 
| 5 | 
            +
                <div class="table-row font-bold">
         | 
| 6 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Type</div>
         | 
| 7 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Identifier</div>
         | 
| 8 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Duration</div>
         | 
| 9 | 
            +
                  <div class="table-cell border-b border-neutral-100 p-2">Happened</div>
         | 
| 10 | 
            +
                </div>
         | 
| 11 | 
            +
              </div>
         | 
| 12 | 
            +
              <div class="table-row-group">
         | 
| 13 | 
            +
                <% @events.each do |event| %>
         | 
| 14 | 
            +
                  <%= link_to signalman_path_for(event), class: "table-row", id: dom_id(event) do %>
         | 
| 15 | 
            +
                    <%= tag.div event.name.split(".").first.humanize, class: "table-cell border-b border-neutral-100 p-2" %>
         | 
| 16 | 
            +
                    <%= tag.div event.payload["identifier"], class: "table-cell border-b border-neutral-100 p-2" %>
         | 
| 17 | 
            +
                    <%= tag.div class: "table-cell border-b border-neutral-100 p-2" do %>
         | 
| 18 | 
            +
                      <%= badge_for_request_duration(event.duration) %>
         | 
| 19 | 
            +
                    <% end %>
         | 
| 20 | 
            +
                    <%= tag.div class: "table-cell border-b border-neutral-100 p-2" do %>
         | 
| 21 | 
            +
                      <%= time_ago_in_words event.started_at %>
         | 
| 22 | 
            +
                    <% end %>
         | 
| 23 | 
            +
                  <% end %>
         | 
| 24 | 
            +
                <% end %>
         | 
| 25 | 
            +
              </div>
         | 
| 26 | 
            +
            </div>
         | 
| 27 | 
            +
             | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            <h1 class="mb-2"><%= @event.name.split(".").first.humanize %></h1>
         | 
| 2 | 
            +
            <div class="text-xs">Started at <%= @event.started_at %></div>
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            <h4>Identifier</h4>
         | 
| 5 | 
            +
            <pre><%= @event.payload["identifier"] %></pre>
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            <% if @event.payload.has_key?("layout") %>
         | 
| 8 | 
            +
              <h4>Layout</h4>
         | 
| 9 | 
            +
              <pre><%= @event.payload["layout"] %></pre>
         | 
| 10 | 
            +
            <% end %>
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            <% if @event.payload.has_key?("count") %>
         | 
| 13 | 
            +
              <h4>Count</h4>
         | 
| 14 | 
            +
              <pre><%= @event.payload["count"] %></pre>
         | 
| 15 | 
            +
            <% end %>
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            <% if @event.payload.has_key?("cache_hits") %>
         | 
| 18 | 
            +
              <h4>Cache Hits</h4>
         | 
| 19 | 
            +
              <pre><%= @event.payload["cache_hits"] %></pre>
         | 
| 20 | 
            +
            <% end %>
         | 
    
        data/config/routes.rb
    ADDED
    
    | @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            Signalman::Engine.routes.draw do
         | 
| 2 | 
            +
              resources :requests
         | 
| 3 | 
            +
              resources :jobs
         | 
| 4 | 
            +
              resources :cache
         | 
| 5 | 
            +
              resources :exceptions
         | 
| 6 | 
            +
              resources :mails
         | 
| 7 | 
            +
              resources :queries
         | 
| 8 | 
            +
              resources :views
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              namespace :generators do
         | 
| 11 | 
            +
                resource :scaffold
         | 
| 12 | 
            +
                resource :model
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              root "requests#index"
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            class CreateSignalmanEvents < ActiveRecord::Migration[7.0]
         | 
| 2 | 
            +
              def change
         | 
| 3 | 
            +
                create_table :signalman_events do |t|
         | 
| 4 | 
            +
                  t.string :name
         | 
| 5 | 
            +
                  t.datetime :started_at
         | 
| 6 | 
            +
                  t.datetime :finished_at
         | 
| 7 | 
            +
                  t.float :duration
         | 
| 8 | 
            +
                  t.json :payload
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  t.timestamps
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                add_index :signalman_events, [:name, :duration]
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            module Signalman
         | 
| 2 | 
            +
              class Engine < ::Rails::Engine
         | 
| 3 | 
            +
                isolate_namespace Signalman
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                initializer "signalman.register_watchers" do
         | 
| 6 | 
            +
                  Signalman.register_watchers
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                # helpers must be accessible anywhere for Turbo broadcasts
         | 
| 10 | 
            +
                initializer 'signalman.helpers' do
         | 
| 11 | 
            +
                  ActiveSupport.on_load :action_controller do
         | 
| 12 | 
            +
                    helper Signalman::EventsHelper
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
    
        data/lib/signalman.rb
    ADDED
    
    | @@ -0,0 +1,183 @@ | |
| 1 | 
            +
            require "signalman/version"
         | 
| 2 | 
            +
            require "signalman/engine"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Signalman
         | 
| 5 | 
            +
              class BaseHandler
         | 
| 6 | 
            +
                attr_reader :current_time, :event
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def self.call(event)
         | 
| 9 | 
            +
                  current_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
         | 
| 10 | 
            +
                  new(event, current_time).start
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def initialize(event, current_time)
         | 
| 14 | 
            +
                  @event, @current_time = event, current_time
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def start
         | 
| 18 | 
            +
                  process unless skip?
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def process
         | 
| 22 | 
            +
                  create_event
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def skip?
         | 
| 26 | 
            +
                  false
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def create_event(payload = nil)
         | 
| 30 | 
            +
                  payload ||= event.payload
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  Event.create(
         | 
| 33 | 
            +
                    name: event.name,
         | 
| 34 | 
            +
                    started_at: started_at,
         | 
| 35 | 
            +
                    finished_at: finished_at,
         | 
| 36 | 
            +
                    duration: event.duration,
         | 
| 37 | 
            +
                    payload: payload
         | 
| 38 | 
            +
                  )
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                # Time measure since system boot with
         | 
| 42 | 
            +
                # Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
         | 
| 43 | 
            +
                def started_at
         | 
| 44 | 
            +
                  Time.current - ((current_time - event.time) / 1_000)
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def finished_at
         | 
| 48 | 
            +
                  Time.current - ((current_time - event.end) / 1_000)
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              class ActionHandler < BaseHandler
         | 
| 53 | 
            +
                def process
         | 
| 54 | 
            +
                  headers = {}
         | 
| 55 | 
            +
                  event.payload.fetch(:headers, {}).each do |name, value|
         | 
| 56 | 
            +
                    headers[name] = value if name.start_with?("HTTP")
         | 
| 57 | 
            +
                    headers[name] = value if ActionDispatch::Http::Headers::CGI_VARIABLES.include?(name)
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    [
         | 
| 60 | 
            +
                      "action_dispatch.request_id"
         | 
| 61 | 
            +
                    ].each do |header_name|
         | 
| 62 | 
            +
                      headers[name] = value if name == header_name
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  create_event event.payload.slice(
         | 
| 67 | 
            +
                      :method,
         | 
| 68 | 
            +
                      :path,
         | 
| 69 | 
            +
                      :controller,
         | 
| 70 | 
            +
                      :action,
         | 
| 71 | 
            +
                      :params,
         | 
| 72 | 
            +
                      :format,
         | 
| 73 | 
            +
                      :status,
         | 
| 74 | 
            +
                      :db_runtime,
         | 
| 75 | 
            +
                      :view_runtime
         | 
| 76 | 
            +
                    ).merge(headers: headers)
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                def skip?
         | 
| 80 | 
            +
                  event.payload[:controller].start_with?("Signalman::")
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
              class ViewHandler < BaseHandler
         | 
| 85 | 
            +
                def skip?
         | 
| 86 | 
            +
                  event.payload[:identifier].include?("app/views/signalman/")
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
              end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
              class QueryHandler < BaseHandler
         | 
| 91 | 
            +
                def skip?
         | 
| 92 | 
            +
                  ["SCHEMA", "TRANSACTION"].include?(event.payload[:name]) ||
         | 
| 93 | 
            +
                    event.payload[:name]&.include?("Signalman::")
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                def process
         | 
| 97 | 
            +
                  create_event event.payload.except(:connection)
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
              class MailHandler < BaseHandler
         | 
| 102 | 
            +
              end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
              class JobHandler < BaseHandler
         | 
| 105 | 
            +
                def process
         | 
| 106 | 
            +
                  job = event.payload[:job]
         | 
| 107 | 
            +
                  create_event(
         | 
| 108 | 
            +
                    class: job.class.name,
         | 
| 109 | 
            +
                    id: job.job_id,
         | 
| 110 | 
            +
                    enqueued_at: job.enqueued_at,
         | 
| 111 | 
            +
                    scheduled_at: scheduled_at(event),
         | 
| 112 | 
            +
                    queue_name: queue_name(event),
         | 
| 113 | 
            +
                    args: args_info(job)
         | 
| 114 | 
            +
                  )
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                # From ActiveJob::LogSubscriber
         | 
| 118 | 
            +
                def queue_name(event)
         | 
| 119 | 
            +
                  # Rails 7.1 -> ActiveJob.adapter_name(event.payload[:adapter]) + "(#{event.payload[:job].queue_name})"
         | 
| 120 | 
            +
                  event.payload[:adapter].class.name.demodulize.remove("Adapter") + "(#{event.payload[:job].queue_name})"
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                def args_info(job)
         | 
| 124 | 
            +
                  if job.class.log_arguments? && job.arguments.any?
         | 
| 125 | 
            +
                    " with arguments: " +
         | 
| 126 | 
            +
                      job.arguments.map { |arg| format(arg).inspect }.join(", ")
         | 
| 127 | 
            +
                  else
         | 
| 128 | 
            +
                    ""
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                def format(arg)
         | 
| 133 | 
            +
                  case arg
         | 
| 134 | 
            +
                  when Hash
         | 
| 135 | 
            +
                    arg.transform_values { |value| format(value) }
         | 
| 136 | 
            +
                  when Array
         | 
| 137 | 
            +
                    arg.map { |value| format(value) }
         | 
| 138 | 
            +
                  when GlobalID::Identification
         | 
| 139 | 
            +
                    arg.to_global_id rescue arg
         | 
| 140 | 
            +
                  else
         | 
| 141 | 
            +
                    arg
         | 
| 142 | 
            +
                  end
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                def scheduled_at(event)
         | 
| 146 | 
            +
                  return unless event.payload[:job].scheduled_at
         | 
| 147 | 
            +
                  Time.at(event.payload[:job].scheduled_at).utc
         | 
| 148 | 
            +
                end
         | 
| 149 | 
            +
              end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
              cattr_accessor :events, default: {
         | 
| 152 | 
            +
                "process_action.action_controller" => {
         | 
| 153 | 
            +
                  handler: ActionHandler,
         | 
| 154 | 
            +
                  path: ->(event) { request_path(event) }
         | 
| 155 | 
            +
                },
         | 
| 156 | 
            +
                /^\w+\.action_view/ => {
         | 
| 157 | 
            +
                  handler: ViewHandler,
         | 
| 158 | 
            +
                  path: ->(event) { view_path(event) }
         | 
| 159 | 
            +
                },
         | 
| 160 | 
            +
                "sql.active_record" => {
         | 
| 161 | 
            +
                  handler: QueryHandler,
         | 
| 162 | 
            +
                  path: ->(event) { query_path(event) }
         | 
| 163 | 
            +
                },
         | 
| 164 | 
            +
                "deliver.action_mailer" => {
         | 
| 165 | 
            +
                  handler: MailHandler,
         | 
| 166 | 
            +
                  path: ->(event) { mail_path(event) }
         | 
| 167 | 
            +
                },
         | 
| 168 | 
            +
                /^\w+\.active_job/ => {
         | 
| 169 | 
            +
                  handler: JobHandler,
         | 
| 170 | 
            +
                  path: ->(event) { job_path(event) }
         | 
| 171 | 
            +
                }
         | 
| 172 | 
            +
              }
         | 
| 173 | 
            +
             | 
| 174 | 
            +
              def self.register_watchers
         | 
| 175 | 
            +
                events.each do |event_name, options|
         | 
| 176 | 
            +
                  options[:subscriber] = add_watcher event_name, options[:handler]
         | 
| 177 | 
            +
                end
         | 
| 178 | 
            +
              end
         | 
| 179 | 
            +
             | 
| 180 | 
            +
              def self.add_watcher(event_name, handler)
         | 
| 181 | 
            +
                ActiveSupport::Notifications.subscribe event_name, handler
         | 
| 182 | 
            +
              end
         | 
| 183 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,98 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: signalman
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Chris Oliver
         | 
| 8 | 
            +
            autorequire:
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2023-08-01 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: rails
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ">="
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: 7.0.0
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ">="
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: 7.0.0
         | 
| 27 | 
            +
            description: Development tools for Ruby on Rails
         | 
| 28 | 
            +
            email:
         | 
| 29 | 
            +
            - excid3@gmail.com
         | 
| 30 | 
            +
            executables: []
         | 
| 31 | 
            +
            extensions: []
         | 
| 32 | 
            +
            extra_rdoc_files: []
         | 
| 33 | 
            +
            files:
         | 
| 34 | 
            +
            - MIT-LICENSE
         | 
| 35 | 
            +
            - README.md
         | 
| 36 | 
            +
            - Rakefile
         | 
| 37 | 
            +
            - app/assets/config/signalman_manifest.js
         | 
| 38 | 
            +
            - app/controllers/signalman/application_controller.rb
         | 
| 39 | 
            +
            - app/controllers/signalman/generators/models_controller.rb
         | 
| 40 | 
            +
            - app/controllers/signalman/generators/scaffolds_controller.rb
         | 
| 41 | 
            +
            - app/controllers/signalman/jobs_controller.rb
         | 
| 42 | 
            +
            - app/controllers/signalman/mails_controller.rb
         | 
| 43 | 
            +
            - app/controllers/signalman/queries_controller.rb
         | 
| 44 | 
            +
            - app/controllers/signalman/requests_controller.rb
         | 
| 45 | 
            +
            - app/controllers/signalman/views_controller.rb
         | 
| 46 | 
            +
            - app/helpers/signalman/events_helper.rb
         | 
| 47 | 
            +
            - app/models/signalman.rb
         | 
| 48 | 
            +
            - app/models/signalman/event.rb
         | 
| 49 | 
            +
            - app/views/layouts/signalman/application.html.erb
         | 
| 50 | 
            +
            - app/views/signalman/generators/models/create.html.erb
         | 
| 51 | 
            +
            - app/views/signalman/generators/models/show.html.erb
         | 
| 52 | 
            +
            - app/views/signalman/generators/scaffolds/create.html.erb
         | 
| 53 | 
            +
            - app/views/signalman/generators/scaffolds/show.html.erb
         | 
| 54 | 
            +
            - app/views/signalman/jobs/index.html.erb
         | 
| 55 | 
            +
            - app/views/signalman/jobs/show.html.erb
         | 
| 56 | 
            +
            - app/views/signalman/mails/index.html.erb
         | 
| 57 | 
            +
            - app/views/signalman/mails/show.html.erb
         | 
| 58 | 
            +
            - app/views/signalman/queries/index.html.erb
         | 
| 59 | 
            +
            - app/views/signalman/queries/show.html.erb
         | 
| 60 | 
            +
            - app/views/signalman/requests/index.html.erb
         | 
| 61 | 
            +
            - app/views/signalman/requests/show.html.erb
         | 
| 62 | 
            +
            - app/views/signalman/shared/_flash.html.erb
         | 
| 63 | 
            +
            - app/views/signalman/shared/_nav.html.erb
         | 
| 64 | 
            +
            - app/views/signalman/views/index.html.erb
         | 
| 65 | 
            +
            - app/views/signalman/views/show.html.erb
         | 
| 66 | 
            +
            - config/routes.rb
         | 
| 67 | 
            +
            - db/migrate/20230729122215_create_signalman_events.rb
         | 
| 68 | 
            +
            - lib/signalman.rb
         | 
| 69 | 
            +
            - lib/signalman/engine.rb
         | 
| 70 | 
            +
            - lib/signalman/version.rb
         | 
| 71 | 
            +
            - lib/tasks/signalman_tasks.rake
         | 
| 72 | 
            +
            homepage: https://github.com/excid3/signalman
         | 
| 73 | 
            +
            licenses:
         | 
| 74 | 
            +
            - MIT
         | 
| 75 | 
            +
            metadata:
         | 
| 76 | 
            +
              homepage_uri: https://github.com/excid3/signalman
         | 
| 77 | 
            +
              source_code_uri: https://github.com/excid3/signalman
         | 
| 78 | 
            +
              changelog_uri: https://github.com/excid3/signalman/blob/main/CHANGELOG.md
         | 
| 79 | 
            +
            post_install_message:
         | 
| 80 | 
            +
            rdoc_options: []
         | 
| 81 | 
            +
            require_paths:
         | 
| 82 | 
            +
            - lib
         | 
| 83 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 84 | 
            +
              requirements:
         | 
| 85 | 
            +
              - - ">="
         | 
| 86 | 
            +
                - !ruby/object:Gem::Version
         | 
| 87 | 
            +
                  version: '0'
         | 
| 88 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 89 | 
            +
              requirements:
         | 
| 90 | 
            +
              - - ">="
         | 
| 91 | 
            +
                - !ruby/object:Gem::Version
         | 
| 92 | 
            +
                  version: '0'
         | 
| 93 | 
            +
            requirements: []
         | 
| 94 | 
            +
            rubygems_version: 3.4.17
         | 
| 95 | 
            +
            signing_key:
         | 
| 96 | 
            +
            specification_version: 4
         | 
| 97 | 
            +
            summary: Development tools for Ruby on Rails
         | 
| 98 | 
            +
            test_files: []
         |