{"id":22117726,"url":"https://github.com/kineticcafe/marlowe","last_synced_at":"2025-07-27T05:33:04.254Z","repository":{"id":47193080,"uuid":"44557724","full_name":"KineticCafe/marlowe","owner":"KineticCafe","description":"Marlowe makes it easier to trace a request through all of your application logs","archived":true,"fork":false,"pushed_at":"2024-02-27T16:27:06.000Z","size":53,"stargazers_count":10,"open_issues_count":0,"forks_count":2,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-07-25T16:46:08.209Z","etag":null,"topics":["correlation-id","rack","rails","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KineticCafe.png","metadata":{"files":{"readme":"README.rdoc","changelog":"History.md","contributing":"Contributing.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-10-19T19:15:03.000Z","updated_at":"2025-04-22T03:08:10.000Z","dependencies_parsed_at":"2024-08-22T21:34:12.065Z","dependency_job_id":"7437861c-3ac9-4bdf-983d-ff669dd2245c","html_url":"https://github.com/KineticCafe/marlowe","commit_stats":{"total_commits":26,"total_committers":6,"mean_commits":4.333333333333333,"dds":0.5384615384615384,"last_synced_commit":"1f288442c2ed4b73c13bc0f10be416da76bf7f99"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/KineticCafe/marlowe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KineticCafe%2Fmarlowe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KineticCafe%2Fmarlowe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KineticCafe%2Fmarlowe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KineticCafe%2Fmarlowe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KineticCafe","download_url":"https://codeload.github.com/KineticCafe/marlowe/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KineticCafe%2Fmarlowe/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267306764,"owners_count":24067035,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-27T02:00:11.917Z","response_time":82,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["correlation-id","rack","rails","ruby"],"created_at":"2024-12-01T13:38:56.694Z","updated_at":"2025-07-27T05:33:03.979Z","avatar_url":"https://github.com/KineticCafe.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"= Marlowe, Your Request Sleuth\n\ncode :: https://github.com/KineticCafe/marlowe/\nissues :: https://github.com/KineticCafe/marlowe/issues\ndocs :: http://www.rubydoc.info/github/KineticCafe/marlowe/master\ncontinuous integration :: {\u003cimg src=\"https://travis-ci.org/KineticCafe/marlowe.svg?branch=master\" alt=\"Build Status\" /\u003e}[https://travis-ci.org/KineticCafe/marlowe]\n\n== Description\n\n{Marlowe}[https://github.com/KineticCafe/marlowe] is a Rack middleware that\nextracts or creates a request ID using a pre-defined header, permitting request\ncorrelation across multiple services.\n\nWhen using Rails, Marlowe automatically adds itself to the middleware before\n\u003ctt\u003eRails::Rack::Logger\u003c/tt\u003e.\n\nAs of Marlowe 3.0, a Faraday middleware is provided (\u003ctt\u003erequire 'marlowe/faraday'\u003c/tt\u003e).\n\n=== Upgrading\n\n==== from Marlowe 2.0\n\nIn Marlowe 2.0, configuration was entirely specified in Rails configuration or\nin the Rack +use+ clause. With the addition of a Faraday middleware for use with\nMarlowe, centralization of the configuration is advisable.\n\nThe existing configuration mechanisms will work (and create instance\nconfigurations if provided), but it is instead recommended to use the global\nconfiguration:\n\n  # Compatibility with Marlowe 1.0\n  Marlowe.configure do |config|\n    config.header = 'Correlation-ID'\n    config.handler = :simple\n    config.return = false\n  end\n\nConfiguration is static for Marlowe::Middleware or Marlowe::Faraday instances\nand changes to Marlowe configuration only affect *new* instances. If the\nconfiguration options are provided in the middleware +use+ clause, they will\noverride the configured values.\n\n  Marlowe.configure do |config|\n    config.header = 'Correlation-ID'\n    config.handler = :simple\n    config.return = false\n  end\n  use Marlowe::Middleware, handler: :clean\n  # The handler will be the :clean handler for the used middleware.\n\n==== from Marlowe 1.x\n\nIn Marlowe 1.0, the correlation header was called \u003ctt\u003eCorrelation-Id\u003c/tt\u003e;\nsince then, Rails 5 and other tools and frameworks (such as Phoenix) have\nstandardized on the header \u003ctt\u003eX-Request-Id\u003c/tt\u003e. Marlowe 2.0 changes to this\nheader by default.\n\nTo keep complete compatibility with Marlowe 1.0, the following should be used:\n\n  # Rails\n  config.marlowe_header = 'Correlation-Id'\n  config.marlowe_handler = :simple\n  config.marlowe_return = false\n\n  # Rack\n  use Marlowe::Middleware, header: 'Correlation-Id', handler: :simple, return: false\n\n== Configuration\n\nMarlowe has three main configuration options: the request ID header, the\nrequest ID handler, and the request ID return. The options may be provided to\nthe Rack +use+ command as a keyword option, or set in a corresponding\n\u003ctt\u003emarlowe_\u003cem\u003eoption\u003c/em\u003e\u003c/tt\u003e configuration variable in Rails.\n\n=== Request ID Header\n\nSpecifies the header to be used for the request correlation ID. Defaults to\n\u003ctt\u003eX-Request-Id\u003c/tt\u003e.\n\n    # Rails\n    config.marlowe_header = 'Correlation-Id'\n    # OR: config.marlowe_correlation_header = 'Correlation-Id'\n\n    # Rack\n    use Marlowe::Middleware, header: 'Correlation-Id'\n    # OR: use Marlowe::Middleware, correlation_header: 'Correlation-Id'\n\nMarlowe will convert this to an appropriate HTTP header (in the Rack +env+\nparameter, the above header would be represented as\n\u003ctt\u003eenv['HTTP_CORRELATION_ID']\u003c/tt\u003e).\n\n=== Request ID Handler\n\nSpecifies the method for sanitizing or generating the request correlation ID.\nValues can be \u003ctt\u003e:clean\u003c/tt\u003e (the default, which limits incoming correlation\nIDs to 255 alphanumeric-or-dash characters), \u003ctt\u003e:simple\u003c/tt\u003e (does not limit\nincoming correlation IDs), or a proc to transform or generate a correlation ID.\n\nIn all cases, if a correlation request ID is not handled, a UUID will be\ngenerated.\n\n    # Rails\n    config.marlowe_handler = :simple\n    config.marlowe_handler = -\u003e(req_id) {\n      req_id.try(:reverse) || SecureRandom.uuid\n    }\n\n    # Rack\n    use Marlowe::Middleware, handler: :simple\n    use Marlowe::Middleware, handler: -\u003e(req_id) {\n      req_id.try(:reverse) || SecureRandom.uuid\n    }\n\n=== Request ID Return\n\nIf +true+ (the default), the request correlation ID will be returned to the\nclient in the same header that it was provided in.\n\n    # Rails\n    config.marlowe_return = false\n\n    # Rack\n    use Marlowe::Middleware, return: false\n\n=== Using Marlowe with Rails 5\n\nRails 5 includes the \u003ctt\u003eActionDispatch::RequestId\u003c/tt\u003e middleware, reducing\nthe need for Marlowe. Marlowe is more configurable than the Rails 5 default, so\nset +marlowe_replace_action_dispatch_request_id+ to true to have\n\u003ctt\u003eMarlowe::Middleware\u003c/tt\u003e will replace \u003ctt\u003eActionDispatch::RequestId\u003c/tt\u003e:\n\n  # Rails only\n  config.marlowe_replace_action_dispatch_request_id = true\n\n== Accessing the Correlation ID\n\nThe correlation id can be accessed throughout the application by accessing the\n{RequestStore}[https://github.com/steveklabnik/request_store] storage.\n\n  RequestStore[:correlation_id]\n\n== Logging\n\nFor a Rails application, you simply need to change the log formatter to one of\nthe provided ones. Correlated versions of both the SimpleFormatter and\nFormatter are included.\n\n  # config/environments/development.rb\n  Rails.application.configure do\n    config.log_formatter = Marlowe::SimpleFormatter.new\n  end\n\nTo create your own formatter, you'll need to access the RequestStore storage.\nYou can use this pattern if you've rolled your own logger/formatter:\n\n  # lib/correlated_formatter.rb\n  require 'request_store'\n\n  class CorrelatedSimpleFormatter \u003c ActiveSupport::Logger::SimpleFormatter\n    def call(severity, timestamp, progname, msg)\n      \"[#{RequestStore.store[:correlation_id]}] #{super}\"\n    end\n  end\n\n=== Lograge\n\nAs {lograge}[https://github.com/roidrage/lograge] supplies its own formatter,\nyou will need to do something a little different:\n\n  # config/application.rb\n\n  class Application \u003c Rails::Application\n    config.before_initialize do\n      ...\n      # use lograge for all request logs\n      config.lograge.enabled = true\n      config.lograge.custom_options = lambda do |event|\n        { correlation_id: RequestStore[:correlation_id] }\n      end\n    end\n  end\n\n=== SemanticLogger\n\nAs {semantic_logger}[https://github.com/rocketjob/semantic_logger] provides its\nown formatters this should be added as a tag. The best way that I can see to do\nthis is to capture the +correlation_id+ in an +on_log+ event:\n\n  # config/initializers/semantic_logger.rb\n\n  SemanticLogger.on_log do |log|\n    if RequestStore[:correlation_id]\n      log.named_tags[:correlation_id] = RequestStore[:correlation_id]\n    end\n  end\n\n== Clients\n\nCatching and creating the correlation ID is a great all on its own, but to\nreally take advantage of the correlation in a service based architecture you'll\nneed to pass the request ID to the next service in the change.\n\nHere's an example with {Faraday}[https://github.com/lostisland/faraday]:\n\n    require 'faraday'\n    require 'faraday_middleware'\n    require 'marlowe/faraday'\n\n    conn = Faraday.new(url: 'https://example.org/') do |conn|\n      conn.request :marlowe\n      conn.request :json\n\n      conn.response :json\n      conn.adapter Faraday.default_adapter\n    end\n\n== Install\n\nAdd Marlowe to your Gemfile:\n\n    gem 'marlowe', '~\u003e 2.0'\n\nOr manually install:\n\n  $ gem install marlowe\n\n== Marlowe Semantic Versioning\n\nMarlowe uses a {Semantic Versioning}[http://semver.org/] scheme with one\nsignificant change:\n\n* When PATCH is zero (+0+), it will be omitted from version references.\n\nAdditionally, the major version will generally be reserved for plug-in\ninfrastructure changes.\n\n== Community and Contributing\n\nMarlowe welcomes your contributions as described in\n{Contributing.md}[https://github.com/KineticCafe/marlowe/blob/master/Contributing.md].\nThis project, like all Kinetic Cafe {open source\nprojects}[https://github.com/KineticCafe], is under the Kinetic Cafe Open\nSource {Code of Conduct}[https://github.com/KineticCafe/code-of-conduct].\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkineticcafe%2Fmarlowe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkineticcafe%2Fmarlowe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkineticcafe%2Fmarlowe/lists"}