sentry-ruby 5.8.0 → 5.12.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sentry/scope.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "sentry/breadcrumb_buffer"
4
+ require "sentry/propagation_context"
4
5
  require "etc"
5
6
 
6
7
  module Sentry
@@ -20,7 +21,8 @@ module Sentry
20
21
  :event_processors,
21
22
  :rack_env,
22
23
  :span,
23
- :session
24
+ :session,
25
+ :propagation_context
24
26
  ]
25
27
 
26
28
  attr_reader(*ATTRIBUTES)
@@ -50,7 +52,10 @@ module Sentry
50
52
  event.transaction_info = { source: transaction_source } if transaction_source
51
53
 
52
54
  if span
53
- event.contexts[:trace] = span.get_trace_context
55
+ event.contexts[:trace] ||= span.get_trace_context
56
+ else
57
+ event.contexts[:trace] ||= propagation_context.get_trace_context
58
+ event.dynamic_sampling_context ||= propagation_context.get_dynamic_sampling_context
54
59
  end
55
60
 
56
61
  event.fingerprint = fingerprint
@@ -95,6 +100,7 @@ module Sentry
95
100
  copy.fingerprint = fingerprint.deep_dup
96
101
  copy.span = span.deep_dup
97
102
  copy.session = session.deep_dup
103
+ copy.propagation_context = propagation_context.deep_dup
98
104
  copy
99
105
  end
100
106
 
@@ -111,6 +117,7 @@ module Sentry
111
117
  self.transaction_sources = scope.transaction_sources
112
118
  self.fingerprint = scope.fingerprint
113
119
  self.span = scope.span
120
+ self.propagation_context = scope.propagation_context
114
121
  end
115
122
 
116
123
  # Updates the scope's data from the given options.
@@ -192,6 +199,10 @@ module Sentry
192
199
  # @return [Hash]
193
200
  def set_contexts(contexts_hash)
194
201
  check_argument_type!(contexts_hash, Hash)
202
+ contexts_hash.values.each do |val|
203
+ check_argument_type!(val, Hash)
204
+ end
205
+
195
206
  @contexts.merge!(contexts_hash) do |key, old, new|
196
207
  old.merge(new)
197
208
  end
@@ -268,6 +279,13 @@ module Sentry
268
279
  @event_processors << block
269
280
  end
270
281
 
282
+ # Generate a new propagation context either from the incoming env headers or from scratch.
283
+ # @param env [Hash, nil]
284
+ # @return [void]
285
+ def generate_propagation_context(env = nil)
286
+ @propagation_context = PropagationContext.new(self, env)
287
+ end
288
+
271
289
  protected
272
290
 
273
291
  # for duplicating scopes internally
@@ -288,6 +306,7 @@ module Sentry
288
306
  @rack_env = {}
289
307
  @span = nil
290
308
  @session = nil
309
+ generate_propagation_context
291
310
  set_new_breadcrumb_buffer
292
311
  end
293
312
 
@@ -305,7 +324,8 @@ module Sentry
305
324
  name: uname[:sysname] || RbConfig::CONFIG["host_os"],
306
325
  version: uname[:version],
307
326
  build: uname[:release],
308
- kernel_version: uname[:version]
327
+ kernel_version: uname[:version],
328
+ machine: uname[:machine]
309
329
  }
310
330
  end
311
331
  end
data/lib/sentry/span.rb CHANGED
@@ -4,6 +4,43 @@ require "securerandom"
4
4
 
5
5
  module Sentry
6
6
  class Span
7
+
8
+ # We will try to be consistent with OpenTelemetry on this front going forward.
9
+ # https://develop.sentry.dev/sdk/performance/span-data-conventions/
10
+ module DataConventions
11
+ URL = "url"
12
+ HTTP_STATUS_CODE = "http.response.status_code"
13
+ HTTP_QUERY = "http.query"
14
+ HTTP_METHOD = "http.request.method"
15
+
16
+ # An identifier for the database management system (DBMS) product being used.
17
+ # Example: postgresql
18
+ DB_SYSTEM = "db.system"
19
+
20
+ # The name of the database being accessed.
21
+ # For commands that switch the database, this should be set to the target database
22
+ # (even if the command fails).
23
+ # Example: myDatabase
24
+ DB_NAME = "db.name"
25
+
26
+ # Name of the database host.
27
+ # Example: example.com
28
+ SERVER_ADDRESS = "server.address"
29
+
30
+ # Logical server port number
31
+ # Example: 80; 8080; 443
32
+ SERVER_PORT = "server.port"
33
+
34
+ # Physical server IP address or Unix socket address.
35
+ # Example: 10.5.3.2
36
+ SERVER_SOCKET_ADDRESS = "server.socket.address"
37
+
38
+ # Physical server port.
39
+ # Recommended: If different than server.port.
40
+ # Example: 16456
41
+ SERVER_SOCKET_PORT = "server.socket.port"
42
+ end
43
+
7
44
  STATUS_MAP = {
8
45
  400 => "invalid_argument",
9
46
  401 => "unauthenticated",
@@ -75,7 +112,7 @@ module Sentry
75
112
  timestamp: nil
76
113
  )
77
114
  @trace_id = trace_id || SecureRandom.uuid.delete("-")
78
- @span_id = span_id || SecureRandom.hex(8)
115
+ @span_id = span_id || SecureRandom.uuid.delete("-").slice(0, 16)
79
116
  @parent_span_id = parent_span_id
80
117
  @sampled = sampled
81
118
  @start_timestamp = start_timestamp || Sentry.utc_now.to_f
@@ -208,7 +245,7 @@ module Sentry
208
245
  # @param status_code [String] example: "500".
209
246
  def set_http_status(status_code)
210
247
  status_code = status_code.to_i
211
- set_data("status_code", status_code)
248
+ set_data(DataConventions::HTTP_STATUS_CODE, status_code)
212
249
 
213
250
  status =
214
251
  if status_code >= 200 && status_code < 299
@@ -14,24 +14,28 @@ module Sentry
14
14
  # @return [void]
15
15
  def setup_sentry_test(&block)
16
16
  raise "please make sure the SDK is initialized for testing" unless Sentry.initialized?
17
- copied_config = Sentry.configuration.dup
17
+ dummy_config = Sentry.configuration.dup
18
18
  # configure dummy DSN, so the events will not be sent to the actual service
19
- copied_config.dsn = DUMMY_DSN
19
+ dummy_config.dsn = DUMMY_DSN
20
20
  # set transport to DummyTransport, so we can easily intercept the captured events
21
- copied_config.transport.transport_class = Sentry::DummyTransport
21
+ dummy_config.transport.transport_class = Sentry::DummyTransport
22
22
  # make sure SDK allows sending under the current environment
23
- copied_config.enabled_environments << copied_config.environment unless copied_config.enabled_environments.include?(copied_config.environment)
23
+ dummy_config.enabled_environments << dummy_config.environment unless dummy_config.enabled_environments.include?(dummy_config.environment)
24
24
  # disble async event sending
25
- copied_config.background_worker_threads = 0
25
+ dummy_config.background_worker_threads = 0
26
26
 
27
27
  # user can overwrite some of the configs, with a few exceptions like:
28
28
  # - include_local_variables
29
29
  # - auto_session_tracking
30
- block&.call(copied_config)
30
+ block&.call(dummy_config)
31
31
 
32
- test_client = Sentry::Client.new(copied_config)
32
+ # the base layer's client should already use the dummy config so nothing will be sent by accident
33
+ base_client = Sentry::Client.new(dummy_config)
34
+ Sentry.get_current_hub.bind_client(base_client)
35
+ # create a new layer so mutations made to the testing scope or configuration could be simply popped later
36
+ Sentry.get_current_hub.push_scope
37
+ test_client = Sentry::Client.new(dummy_config.dup)
33
38
  Sentry.get_current_hub.bind_client(test_client)
34
- Sentry.get_current_scope.clear
35
39
  end
36
40
 
37
41
  # Clears all stored events and envelopes.
@@ -40,9 +44,12 @@ module Sentry
40
44
  def teardown_sentry_test
41
45
  return unless Sentry.initialized?
42
46
 
43
- sentry_transport.events = []
44
- sentry_transport.envelopes = []
45
- Sentry.get_current_scope.clear
47
+ # pop testing layer created by `setup_sentry_test`
48
+ # but keep the base layer to avoid nil-pointer errors
49
+ # TODO: find a way to notify users if they somehow popped the test layer before calling this method
50
+ if Sentry.get_current_hub.instance_variable_get(:@stack).size > 1
51
+ Sentry.get_current_hub.pop_scope
52
+ end
46
53
  end
47
54
 
48
55
  # @return [Transport]
@@ -75,4 +82,3 @@ module Sentry
75
82
  end
76
83
  end
77
84
  end
78
-
@@ -1,16 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "sentry/baggage"
4
+ require "sentry/profiler"
5
+ require "sentry/propagation_context"
4
6
 
5
7
  module Sentry
6
8
  class Transaction < Span
7
- SENTRY_TRACE_REGEXP = Regexp.new(
8
- "^[ \t]*" + # whitespace
9
- "([0-9a-f]{32})?" + # trace_id
10
- "-?([0-9a-f]{16})?" + # span_id
11
- "-?([01])?" + # sampled
12
- "[ \t]*$" # whitespace
13
- )
9
+ # @deprecated Use Sentry::PropagationContext::SENTRY_TRACE_REGEXP instead.
10
+ SENTRY_TRACE_REGEXP = PropagationContext::SENTRY_TRACE_REGEXP
11
+
14
12
  UNLABELD_NAME = "<unlabeled transaction>".freeze
15
13
  MESSAGE_PREFIX = "[Tracing]"
16
14
 
@@ -58,6 +56,10 @@ module Sentry
58
56
  # @return [Hash]
59
57
  attr_reader :contexts
60
58
 
59
+ # The Profiler instance for this transaction.
60
+ # @return [Profiler]
61
+ attr_reader :profiler
62
+
61
63
  def initialize(
62
64
  hub:,
63
65
  name: nil,
@@ -83,9 +85,12 @@ module Sentry
83
85
  @effective_sample_rate = nil
84
86
  @contexts = {}
85
87
  @measurements = {}
88
+ @profiler = Profiler.new(@configuration)
86
89
  init_span_recorder
87
90
  end
88
91
 
92
+ # @deprecated use Sentry.continue_trace instead.
93
+ #
89
94
  # Initalizes a Transaction instance with a Sentry trace string from another transaction (usually from an external request).
90
95
  #
91
96
  # The original transaction will become the parent of the new Transaction instance. And they will share the same `trace_id`.
@@ -126,18 +131,10 @@ module Sentry
126
131
  )
127
132
  end
128
133
 
129
- # Extract the trace_id, parent_span_id and parent_sampled values from a sentry-trace header.
130
- #
131
- # @param sentry_trace [String] the sentry-trace header value from the previous transaction.
134
+ # @deprecated Use Sentry::PropagationContext.extract_sentry_trace instead.
132
135
  # @return [Array, nil]
133
136
  def self.extract_sentry_trace(sentry_trace)
134
- match = SENTRY_TRACE_REGEXP.match(sentry_trace)
135
- return nil if match.nil?
136
-
137
- trace_id, parent_span_id, sampled_flag = match[1..3]
138
- parent_sampled = sampled_flag.nil? ? nil : sampled_flag != "0"
139
-
140
- [trace_id, parent_span_id, parent_sampled]
137
+ PropagationContext.extract_sentry_trace(sentry_trace)
141
138
  end
142
139
 
143
140
  # @return [Hash]
@@ -254,6 +251,8 @@ module Sentry
254
251
  @name = UNLABELD_NAME
255
252
  end
256
253
 
254
+ @profiler.stop
255
+
257
256
  if @sampled
258
257
  event = hub.current_client.event_from_transaction(self)
259
258
  hub.capture_event(event)
@@ -288,6 +287,13 @@ module Sentry
288
287
  @contexts[key] = value
289
288
  end
290
289
 
290
+ # Start the profiler.
291
+ # @return [void]
292
+ def start_profiler!
293
+ profiler.set_initial_sample_decision(sampled)
294
+ profiler.start
295
+ end
296
+
291
297
  protected
292
298
 
293
299
  def init_span_recorder(limit = 1000)
@@ -308,6 +314,7 @@ module Sentry
308
314
  items = {
309
315
  "trace_id" => trace_id,
310
316
  "sample_rate" => effective_sample_rate&.to_s,
317
+ "sampled" => sampled&.to_s,
311
318
  "environment" => @environment,
312
319
  "release" => @release,
313
320
  "public_key" => @dsn&.public_key
@@ -8,15 +8,15 @@ module Sentry
8
8
  # @return [<Array[Span]>]
9
9
  attr_accessor :spans
10
10
 
11
- # @return [Hash, nil]
12
- attr_accessor :dynamic_sampling_context
13
-
14
11
  # @return [Hash]
15
12
  attr_accessor :measurements
16
13
 
17
14
  # @return [Float, nil]
18
15
  attr_reader :start_timestamp
19
16
 
17
+ # @return [Hash, nil]
18
+ attr_accessor :profile
19
+
20
20
  def initialize(transaction:, **options)
21
21
  super(**options)
22
22
 
@@ -32,6 +32,8 @@ module Sentry
32
32
 
33
33
  finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
34
34
  self.spans = finished_spans.map(&:to_hash)
35
+
36
+ populate_profile(transaction)
35
37
  end
36
38
 
37
39
  # Sets the event's start_timestamp.
@@ -49,5 +51,30 @@ module Sentry
49
51
  data[:measurements] = @measurements
50
52
  data
51
53
  end
54
+
55
+ private
56
+
57
+ def populate_profile(transaction)
58
+ profile_hash = transaction.profiler.to_hash
59
+ return if profile_hash.empty?
60
+
61
+ profile_hash.merge!(
62
+ environment: environment,
63
+ release: release,
64
+ timestamp: Time.at(start_timestamp).iso8601,
65
+ device: { architecture: Scope.os_context[:machine] },
66
+ os: { name: Scope.os_context[:name], version: Scope.os_context[:version] },
67
+ runtime: Scope.runtime_context,
68
+ transaction: {
69
+ id: event_id,
70
+ name: transaction.name,
71
+ trace_id: transaction.trace_id,
72
+ # TODO-neel-profiler stubbed for now, see thread_id note in profiler.rb
73
+ active_thead_id: '0'
74
+ }
75
+ )
76
+
77
+ self.profile = profile_hash
78
+ end
52
79
  end
53
80
  end
@@ -18,7 +18,8 @@ module Sentry
18
18
  :network_error,
19
19
  :sample_rate,
20
20
  :before_send,
21
- :event_processor
21
+ :event_processor,
22
+ :insufficient_data
22
23
  ]
23
24
 
24
25
  include LoggingHelper
@@ -143,7 +144,7 @@ module Sentry
143
144
  sent_at: Sentry.utc_now.iso8601
144
145
  }
145
146
 
146
- if event.is_a?(TransactionEvent) && event.dynamic_sampling_context
147
+ if event.is_a?(Event) && event.dynamic_sampling_context
147
148
  envelope_headers[:trace] = event.dynamic_sampling_context
148
149
  end
149
150
 
@@ -154,6 +155,13 @@ module Sentry
154
155
  event_payload
155
156
  )
156
157
 
158
+ if event.is_a?(TransactionEvent) && event.profile
159
+ envelope.add_item(
160
+ { type: 'profile', content_type: 'application/json' },
161
+ event.profile
162
+ )
163
+ end
164
+
157
165
  client_report_headers, client_report_payload = fetch_pending_client_report
158
166
  envelope.add_item(client_report_headers, client_report_payload) if client_report_headers
159
167
 
@@ -178,7 +186,7 @@ module Sentry
178
186
  reason, type = key
179
187
 
180
188
  # 'event' has to be mapped to 'error'
181
- category = type == 'transaction' ? 'transaction' : 'error'
189
+ category = type == 'event' ? 'error' : type
182
190
 
183
191
  { reason: reason, category: category, quantity: val }
184
192
  end
@@ -4,9 +4,15 @@ module Sentry
4
4
  module ArgumentCheckingHelper
5
5
  private
6
6
 
7
- def check_argument_type!(argument, expected_type)
8
- unless argument.is_a?(expected_type)
9
- raise ArgumentError, "expect the argument to be a #{expected_type}, got #{argument.class} (#{argument.inspect})"
7
+ def check_argument_type!(argument, *expected_types)
8
+ unless expected_types.any? { |t| argument.is_a?(t) }
9
+ raise ArgumentError, "expect the argument to be a #{expected_types.join(' or ')}, got #{argument.class} (#{argument.inspect})"
10
+ end
11
+ end
12
+
13
+ def check_argument_includes!(argument, values)
14
+ unless values.include?(argument)
15
+ raise ArgumentError, "expect the argument to be one of #{values.map(&:inspect).join(' or ')}, got #{argument.inspect}"
10
16
  end
11
17
  end
12
18
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "5.8.0"
4
+ VERSION = "5.12.0"
5
5
  end
data/lib/sentry-ruby.rb CHANGED
@@ -15,11 +15,13 @@ require "sentry/logger"
15
15
  require "sentry/event"
16
16
  require "sentry/error_event"
17
17
  require "sentry/transaction_event"
18
+ require "sentry/check_in_event"
18
19
  require "sentry/span"
19
20
  require "sentry/transaction"
20
21
  require "sentry/hub"
21
22
  require "sentry/background_worker"
22
23
  require "sentry/session_flusher"
24
+ require "sentry/cron/monitor_check_ins"
23
25
 
24
26
  [
25
27
  "sentry/rake",
@@ -73,8 +75,18 @@ module Sentry
73
75
  ##### Patch Registration #####
74
76
 
75
77
  # @!visibility private
76
- def register_patch(&block)
77
- registered_patches << block
78
+ def register_patch(patch = nil, target = nil, &block)
79
+ if patch && block
80
+ raise ArgumentError.new("Please provide either a patch and its target OR a block, but not both")
81
+ end
82
+
83
+ if block
84
+ registered_patches << block
85
+ else
86
+ registered_patches << proc do
87
+ target.send(:prepend, patch) unless target.ancestors.include?(patch)
88
+ end
89
+ end
78
90
  end
79
91
 
80
92
  # @!visibility private
@@ -420,6 +432,24 @@ module Sentry
420
432
  get_current_hub.capture_event(event)
421
433
  end
422
434
 
435
+ # Captures a check-in and sends it to Sentry via the currently active hub.
436
+ #
437
+ # @param slug [String] identifier of this monitor
438
+ # @param status [Symbol] status of this check-in, one of {CheckInEvent::VALID_STATUSES}
439
+ #
440
+ # @param [Hash] options extra check-in options
441
+ # @option options [String] check_in_id for updating the status of an existing monitor
442
+ # @option options [Integer] duration seconds elapsed since this monitor started
443
+ # @option options [Cron::MonitorConfig] monitor_config configuration for this monitor
444
+ #
445
+ # @yieldparam scope [Scope]
446
+ #
447
+ # @return [String, nil] The {CheckInEvent#check_in_id} to use for later updates on the same slug
448
+ def capture_check_in(slug, status, **options, &block)
449
+ return unless initialized?
450
+ get_current_hub.capture_check_in(slug, status, **options, &block)
451
+ end
452
+
423
453
  # Takes or initializes a new Sentry::Transaction and makes a sampling decision for it.
424
454
  #
425
455
  # @return [Transaction, nil]
@@ -479,6 +509,42 @@ module Sentry
479
509
  Scope.add_global_event_processor(&block)
480
510
  end
481
511
 
512
+ # Returns the traceparent (sentry-trace) header for distributed tracing.
513
+ # Can be either from the currently active span or the propagation context.
514
+ #
515
+ # @return [String, nil]
516
+ def get_traceparent
517
+ return nil unless initialized?
518
+ get_current_hub.get_traceparent
519
+ end
520
+
521
+ # Returns the baggage header for distributed tracing.
522
+ # Can be either from the currently active span or the propagation context.
523
+ #
524
+ # @return [String, nil]
525
+ def get_baggage
526
+ return nil unless initialized?
527
+ get_current_hub.get_baggage
528
+ end
529
+
530
+ # Returns the a Hash containing sentry-trace and baggage.
531
+ # Can be either from the currently active span or the propagation context.
532
+ #
533
+ # @return [Hash, nil]
534
+ def get_trace_propagation_headers
535
+ return nil unless initialized?
536
+ get_current_hub.get_trace_propagation_headers
537
+ end
538
+
539
+ # Continue an incoming trace from a rack env like hash.
540
+ #
541
+ # @param env [Hash]
542
+ # @return [Transaction, nil]
543
+ def continue_trace(env, **options)
544
+ return nil unless initialized?
545
+ get_current_hub.continue_trace(env, **options)
546
+ end
547
+
482
548
  ##### Helpers #####
483
549
 
484
550
  # @!visibility private
@@ -509,3 +575,4 @@ end
509
575
  # patches
510
576
  require "sentry/net/http"
511
577
  require "sentry/redis"
578
+ require "sentry/puma"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.8.0
4
+ version: 5.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-06 00:00:00.000000000 Z
11
+ date: 2023-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -42,7 +42,6 @@ files:
42
42
  - ".rspec"
43
43
  - ".yardopts"
44
44
  - CHANGELOG.md
45
- - CODE_OF_CONDUCT.md
46
45
  - Gemfile
47
46
  - LICENSE.txt
48
47
  - Makefile
@@ -57,10 +56,14 @@ files:
57
56
  - lib/sentry/breadcrumb.rb
58
57
  - lib/sentry/breadcrumb/sentry_logger.rb
59
58
  - lib/sentry/breadcrumb_buffer.rb
59
+ - lib/sentry/check_in_event.rb
60
60
  - lib/sentry/client.rb
61
61
  - lib/sentry/configuration.rb
62
62
  - lib/sentry/core_ext/object/deep_dup.rb
63
63
  - lib/sentry/core_ext/object/duplicable.rb
64
+ - lib/sentry/cron/monitor_check_ins.rb
65
+ - lib/sentry/cron/monitor_config.rb
66
+ - lib/sentry/cron/monitor_schedule.rb
64
67
  - lib/sentry/dsn.rb
65
68
  - lib/sentry/envelope.rb
66
69
  - lib/sentry/error_event.rb
@@ -78,6 +81,9 @@ files:
78
81
  - lib/sentry/linecache.rb
79
82
  - lib/sentry/logger.rb
80
83
  - lib/sentry/net/http.rb
84
+ - lib/sentry/profiler.rb
85
+ - lib/sentry/propagation_context.rb
86
+ - lib/sentry/puma.rb
81
87
  - lib/sentry/rack.rb
82
88
  - lib/sentry/rack/capture_exceptions.rb
83
89
  - lib/sentry/rake.rb
data/CODE_OF_CONDUCT.md DELETED
@@ -1,74 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- In the interest of fostering an open and welcoming environment, we as
6
- contributors and maintainers pledge to making participation in our project and
7
- our community a harassment-free experience for everyone, regardless of age, body
8
- size, disability, ethnicity, gender identity and expression, level of experience,
9
- nationality, personal appearance, race, religion, or sexual identity and
10
- orientation.
11
-
12
- ## Our Standards
13
-
14
- Examples of behavior that contributes to creating a positive environment
15
- include:
16
-
17
- * Using welcoming and inclusive language
18
- * Being respectful of differing viewpoints and experiences
19
- * Gracefully accepting constructive criticism
20
- * Focusing on what is best for the community
21
- * Showing empathy towards other community members
22
-
23
- Examples of unacceptable behavior by participants include:
24
-
25
- * The use of sexualized language or imagery and unwelcome sexual attention or
26
- advances
27
- * Trolling, insulting/derogatory comments, and personal or political attacks
28
- * Public or private harassment
29
- * Publishing others' private information, such as a physical or electronic
30
- address, without explicit permission
31
- * Other conduct which could reasonably be considered inappropriate in a
32
- professional setting
33
-
34
- ## Our Responsibilities
35
-
36
- Project maintainers are responsible for clarifying the standards of acceptable
37
- behavior and are expected to take appropriate and fair corrective action in
38
- response to any instances of unacceptable behavior.
39
-
40
- Project maintainers have the right and responsibility to remove, edit, or
41
- reject comments, commits, code, wiki edits, issues, and other contributions
42
- that are not aligned to this Code of Conduct, or to ban temporarily or
43
- permanently any contributor for other behaviors that they deem inappropriate,
44
- threatening, offensive, or harmful.
45
-
46
- ## Scope
47
-
48
- This Code of Conduct applies both within project spaces and in public spaces
49
- when an individual is representing the project or its community. Examples of
50
- representing a project or community include using an official project e-mail
51
- address, posting via an official social media account, or acting as an appointed
52
- representative at an online or offline event. Representation of a project may be
53
- further defined and clarified by project maintainers.
54
-
55
- ## Enforcement
56
-
57
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at stan001212@gmail.com. All
59
- complaints will be reviewed and investigated and will result in a response that
60
- is deemed necessary and appropriate to the circumstances. The project team is
61
- obligated to maintain confidentiality with regard to the reporter of an incident.
62
- Further details of specific enforcement policies may be posted separately.
63
-
64
- Project maintainers who do not follow or enforce the Code of Conduct in good
65
- faith may face temporary or permanent repercussions as determined by other
66
- members of the project's leadership.
67
-
68
- ## Attribution
69
-
70
- This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
- available at [https://contributor-covenant.org/version/1/4][version]
72
-
73
- [homepage]: https://contributor-covenant.org
74
- [version]: https://contributor-covenant.org/version/1/4/