Add bin and edit workflow
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 9s

This commit is contained in:
2026-09-16 13:11:16 -06:00
parent c8ac4fcae5
commit 4cee170d66
17576 changed files with 895740 additions and 2 deletions
+11
View File
@@ -0,0 +1,11 @@
# frozen_string_literal: true
# Released under the MIT License.
# Copyright, 2021-2022, by Samuel Williams.
require_relative 'traces/version'
require_relative 'traces/provider'
# @namespace
module Traces
end
@@ -0,0 +1,26 @@
# frozen_string_literal: true
# Released under the MIT License.
# Copyright, 2021-2025, by Samuel Williams.
require_relative 'config'
module Traces
# The backend implementation is responsible for recording and reporting traces.
module Backend
end
# This is a default implementation, which can be replaced by the backend.
# @returns [Object] The current trace context.
def self.trace_context
nil
end
# This is a default implementation, which can be replaced by the backend.
# @returns [Boolean] Whether there is an active trace.
def self.active?
!!self.trace_context
end
Config::DEFAULT.require_backend
end
@@ -0,0 +1,97 @@
# frozen_string_literal: true
# Released under the MIT License.
# Copyright, 2023, by Samuel Williams.
require_relative '../context'
require 'fiber'
Fiber.attr_accessor :traces_backend_context
module Traces
module Backend
# A backend which logs all spans to the Capture logger output.
module Capture
# A span which validates tag assignment.
class Span
# Initialize a new span.
# @parameter context [Context] The context in which the span is recorded.
# @parameter name [String] A useful name/annotation for the recorded span.
# @parameter resource [String] The "resource" that the span is associated with.
# @parameter attributes [Hash] Metadata for the recorded span.
def initialize(context, name, resource, attributes)
@context = context
@name = name
@resource = resource
@attributes = attributes
end
attr :context
attr :name
attr :resource
attr :attributes
# Assign some metadata to the span.
# @parameter key [String] The metadata key.
# @parameter value [Object] The metadata value. Should be coercable to a string.
def []= key, value
@attributes[key] = value
end
# Convert the span to a JSON representation.
def as_json
{
name: @name,
resource: @resource,
attributes: @attributes,
context: @context.as_json
}
end
# Convert the span to a JSON string.
def to_json(...)
as_json.to_json(...)
end
end
# All captured spans.
def self.spans
@spans ||= []
end
# The capture backend interface.
module Interface
# Trace the given block of code and log the execution.
# @parameter name [String] A useful name/annotation for the recorded span.
# @parameter attributes [Hash] Metadata for the recorded span.
def trace(name, resource: nil, attributes: {}, &block)
context = Context.nested(Fiber.current.traces_backend_context)
Fiber.current.traces_backend_context = context
span = Span.new(context, name, resource, attributes)
Capture.spans << span
yield span
end
# Assign a trace context to the current execution scope.
def trace_context= context
Fiber.current.traces_backend_context = context
end
# Get a trace context from the current execution scope.
def trace_context
Fiber.current.traces_backend_context
end
# @returns [Boolean] Whether there is an active trace.
def active?
!!Fiber.current.traces_backend_context
end
end
end
Interface = Capture::Interface
end
end
@@ -0,0 +1,75 @@
# frozen_string_literal: true
# Released under the MIT License.
# Copyright, 2021-2023, by Samuel Williams.
require_relative '../context'
require 'console'
require 'fiber'
Fiber.attr_accessor :traces_backend_context
module Traces
module Backend
# A backend which logs all spans to the console logger output.
module Console
# A span which validates tag assignment.
class Span
# Initialize a new span.
# @parameter context [Context] The context in which the span is recorded.
# @parameter name [String] A useful name/annotation for the recorded span.
def initialize(context, name)
@context = context
@name = name
end
# @attribute [Context] The context in which the span is recorded.
attr :context
# Assign some metadata to the span.
# @parameter key [String] The metadata key.
# @parameter value [Object] The metadata value. Should be coercable to a string.
def []= key, value
::Console.logger.info(@context, @name, "#{key} = #{value}")
end
end
# The console backend interface.
module Interface
# Trace the given block of code and log the execution.
# @parameter name [String] A useful name/annotation for the recorded span.
# @parameter attributes [Hash] Metadata for the recorded span.
def trace(name, resource: nil, attributes: {}, &block)
context = Context.nested(Fiber.current.traces_backend_context)
Fiber.current.traces_backend_context = context
::Console.logger.info(resource || self, name, attributes)
if block.arity.zero?
yield
else
yield Span.new(context, name)
end
end
# Assign a trace context to the current execution scope.
def trace_context= context
Fiber.current.traces_backend_context = context
end
# Get a trace context from the current execution scope.
def trace_context
Fiber.current.traces_backend_context
end
# @returns [Boolean] Whether there is an active trace.
def active?
!!Fiber.current.traces_backend_context
end
end
end
Interface = Console::Interface
end
end
@@ -0,0 +1,99 @@
# frozen_string_literal: true
# Released under the MIT License.
# Copyright, 2021-2023, by Samuel Williams.
require_relative '../context'
require 'fiber'
Fiber.attr_accessor :traces_backend_context
module Traces
module Backend
# A backend which validates interface usage.
module Test
# A span which validates tag assignment.
class Span
# Initialize a new span.
# @parameter context [Context] The context in which the span is recorded.
def initialize(context)
@context = context
end
# @attribute [Context] The context in which the span is recorded.
attr :context
# Assign some metadata to the span.
# @parameter key [String] The metadata key.
# @parameter value [Object] The metadata value. Should be coercable to a string.
def []= key, value
unless key.is_a?(String) || key.is_a?(Symbol)
raise ArgumentError, "Invalid attribute key (must be String or Symbol): #{key.inspect}!"
end
begin
String(value)
rescue
raise ArgumentError, "Invalid attribute value (must be convertible to String): #{value.inspect}!"
end
end
end
# The test backend interface.
module Interface
# Trace the given block of code and validate the interface usage.
# @parameter name [String] A useful name/annotation for the recorded span.
# @parameter resource [String] The context in which the trace operation is occuring.
# @parameter attributes [Hash] Metadata for the recorded span.
def trace(name, resource: nil, attributes: nil, &block)
unless block_given?
raise ArgumentError, "No block given!"
end
unless name.is_a?(String)
raise ArgumentError, "Invalid name (must be String): #{name.inspect}!"
end
# It should be convertable:
resource &&= resource.to_s
context = Context.nested(Fiber.current.traces_backend_context)
span = Span.new(context)
# Ensure the attributes are valid and follow the requirements:
attributes&.each do |key, value|
span[key] = value
end
Fiber.current.traces_backend_context = context
if block.arity.zero?
yield
else
yield span
end
end
# Assign a trace context to the current execution scope.
def trace_context= context
Fiber.current.traces_backend_context = context
end
# Get a trace context from the current execution scope.
def trace_context
Fiber.current.traces_backend_context
end
# @returns [Boolean] Whether there is an active trace.
def active?
# For the sake of testing, we always enable tracing.
true
end
end
end
Interface = Test::Interface
end
end
@@ -0,0 +1,55 @@
# frozen_string_literal: true
# Released under the MIT License.
# Copyright, 2024-2025, by Samuel Williams.
module Traces
# Represents a configuration for the traces library.
class Config
DEFAULT_PATH = ENV.fetch("TRACES_CONFIG_DEFAULT_PATH", "config/traces.rb")
# Load the configuration from the given path.
# @parameter path [String] The path to the configuration file.
# @returns [Config] The loaded configuration.
def self.load(path)
config = self.new
if File.exist?(path)
config.instance_eval(File.read(path), path)
end
return config
end
# Load the default configuration.
# @returns [Config] The default configuration.
def self.default
@default ||= self.load(DEFAULT_PATH)
end
# Prepare the backend, e.g. by loading additional libraries or instrumentation.
def prepare
end
# Require a specific traces backend implementation.
def require_backend(env = ENV)
if backend = env['TRACES_BACKEND']
begin
if require(backend)
# We ensure that the interface methods replace any existing methods by prepending the module:
Traces.singleton_class.prepend(Backend::Interface)
return true
end
rescue LoadError => error
warn "Unable to load traces backend: #{backend.inspect}!"
end
end
return false
end
# Load the default configuration.
DEFAULT = self.default
end
end
@@ -0,0 +1,112 @@
# frozen_string_literal: true
# Released under the MIT License.
# Copyright, 2021-2023, by Samuel Williams.
require 'securerandom'
module Traces
# A generic representation of the current tracing context.
class Context
# Parse a string representation of a distributed trace.
# @parameter parent [String] The parent trace context.
# @parameter state [Array(String)] Any attached trace state.
def self.parse(parent, state = nil, **options)
version, trace_id, parent_id, flags = parent.split('-')
if version == '00'
flags = Integer(flags, 16)
if state.is_a?(String)
state = state.split(',')
end
if state
state = state.map{|item| item.split('=')}.to_h
end
self.new(trace_id, parent_id, flags, state, **options)
end
end
# Create a local trace context which is likley to be globally unique.
# @parameter flags [Integer] Any trace context flags.
def self.local(flags = 0, **options)
self.new(SecureRandom.hex(16), SecureRandom.hex(8), flags, **options)
end
# Nest a local trace context in an optional parent context.
# @parameter parent [Context] An optional parent context.
def self.nested(parent, flags = 0)
if parent
parent.nested(flags)
else
self.local(flags)
end
end
SAMPLED = 0x01
# Initialize the trace context.
# @parameter trace_id [String] The ID of the whole trace forest.
# @parameter parent_id [String] The ID of this operation as known by the caller (sometimes referred to as the span ID).
# @parameter flags [Integer] An 8-bit field that controls tracing flags such as sampling, trace level, etc.
# @parameter state [Hash] Additional vendor-specific trace identification information.
# @parameter remote [Boolean] Whether this context was created from a distributed trace header.
def initialize(trace_id, parent_id, flags, state = nil, remote: false)
@trace_id = trace_id
@parent_id = parent_id
@flags = flags
@state = state
@remote = remote
end
# Create a new nested trace context in which spans can be recorded.
def nested(flags = @flags)
Context.new(@trace_id, SecureRandom.hex(8), flags, @state, remote: @remote)
end
# The ID of the whole trace forest and is used to uniquely identify a distributed trace through a system. It is represented as a 16-byte array, for example, 4bf92f3577b34da6a3ce929d0e0e4736. All bytes as zero (00000000000000000000000000000000) is considered an invalid value.
attr :trace_id
# The ID of this operation as known by the caller (in some tracing systems, this is known as the span-id, where a span is the execution of a client operation). It is represented as an 8-byte array, for example, 00f067aa0ba902b7. All bytes as zero (0000000000000000) is considered an invalid value.
attr :parent_id
# An 8-bit field that controls tracing flags such as sampling, trace level, etc. These flags are recommendations given by the caller rather than strict rules.
attr :flags
# Provides additional vendor-specific trace identification information across different distributed tracing systems. Conveys information about the operation's position in multiple distributed tracing graphs.
attr :state
# Denotes that the caller may have recorded trace data. When unset, the caller did not record trace data out-of-band.
def sampled?
(@flags & SAMPLED) != 0
end
# Whether this context was created from a distributed trace header.
def remote?
@remote
end
# A string representation of the trace context (excluding trace state).
def to_s
"00-#{@trace_id}-#{@parent_id}-#{@flags.to_s(16)}"
end
# Convert the trace context to a JSON representation, including trace state.
def as_json
{
trace_id: @trace_id,
parent_id: @parent_id,
flags: @flags,
state: @state,
remote: @remote
}
end
# Convert the trace context to a JSON string.
def to_json(...)
as_json.to_json(...)
end
end
end
@@ -0,0 +1,46 @@
# frozen_string_literal: true
# Released under the MIT License.
# Copyright, 2021-2023, by Samuel Williams.
require_relative 'backend'
module Traces
# @returns [Boolean] Whether there is an active backend.
def self.enabled?
Backend.const_defined?(:Interface)
end
# @namespace
module Provider
end
module Singleton
# A module which contains tracing specific wrappers.
def traces_provider
@traces_provider ||= Module.new
end
end
private_constant :Singleton
# Bail out if there is no backend configured.
if self.enabled?
# Extend the specified class in order to emit traces.
def self.Provider(klass, &block)
klass.extend(Singleton)
provider = klass.traces_provider
klass.prepend(provider)
provider.module_exec(&block) if block_given?
return provider
end
Config::DEFAULT.prepare
else
def self.Provider(klass, &block)
# Tracing disabled.
end
end
end
@@ -0,0 +1,8 @@
# frozen_string_literal: true
# Released under the MIT License.
# Copyright, 2021-2023, by Samuel Williams.
module Traces
VERSION = "0.15.2"
end