dicom 0.9.1 → 0.9.2
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.
- data/CHANGELOG.rdoc +17 -0
- data/README.rdoc +16 -3
- data/lib/dicom.rb +3 -1
- data/lib/dicom/anonymizer.rb +35 -54
- data/lib/dicom/d_client.rb +49 -64
- data/lib/dicom/d_object.rb +511 -416
- data/lib/dicom/d_read.rb +21 -34
- data/lib/dicom/d_server.rb +21 -61
- data/lib/dicom/d_write.rb +3 -6
- data/lib/dicom/element.rb +1 -1
- data/lib/dicom/file_handler.rb +14 -9
- data/lib/dicom/image_item.rb +7 -6
- data/lib/dicom/link.rb +42 -77
- data/lib/dicom/logging.rb +158 -0
- data/lib/dicom/parent.rb +9 -8
- data/lib/dicom/sequence.rb +1 -1
- data/lib/dicom/version.rb +1 -1
- metadata +5 -4
data/lib/dicom/link.rb
CHANGED
@@ -3,6 +3,7 @@ module DICOM
|
|
3
3
|
# This class handles the construction and interpretation of network packages as well as network communication.
|
4
4
|
#
|
5
5
|
class Link
|
6
|
+
include Logging
|
6
7
|
|
7
8
|
# A customized FileHandler class to use instead of the default FileHandler included with Ruby DICOM.
|
8
9
|
attr_accessor :file_handler
|
@@ -10,12 +11,6 @@ module DICOM
|
|
10
11
|
attr_accessor :max_package_size
|
11
12
|
# A hash which keeps track of the relationship between context ID and chosen transfer syntax.
|
12
13
|
attr_accessor :presentation_contexts
|
13
|
-
# A boolean which defines if notices/warnings/errors will be printed to the screen (true) or not (false).
|
14
|
-
attr_accessor :verbose
|
15
|
-
# An array containing any error messages recorded.
|
16
|
-
attr_reader :errors
|
17
|
-
# An array containing any status messages recorded.
|
18
|
-
attr_reader :notices
|
19
14
|
# A TCP network session where the DICOM communication is done with a remote host or client.
|
20
15
|
attr_reader :session
|
21
16
|
|
@@ -32,7 +27,6 @@ module DICOM
|
|
32
27
|
# * <tt>:host_ae</tt> -- String. The name of the server (application entity).
|
33
28
|
# * <tt>:max_package_size</tt> -- Fixnum. The maximum allowed size of network packages (in bytes).
|
34
29
|
# * <tt>:timeout</tt> -- Fixnum. The maximum period to wait for an answer before aborting the communication.
|
35
|
-
# * <tt>:verbose</tt> -- Boolean. If set to false, the DLink instance will run silently and not output warnings and error messages to the screen. Defaults to true.
|
36
30
|
#
|
37
31
|
def initialize(options={})
|
38
32
|
require 'socket'
|
@@ -44,11 +38,6 @@ module DICOM
|
|
44
38
|
@max_receive_size = @max_package_size
|
45
39
|
@timeout = options[:timeout] || 10 # seconds
|
46
40
|
@min_length = 10 # minimum number of bytes to expect in an incoming transmission
|
47
|
-
@verbose = options[:verbose]
|
48
|
-
@verbose = true if @verbose == nil # Default verbosity is 'on'.
|
49
|
-
# Other instance variables:
|
50
|
-
@errors = Array.new # errors and warnings are put in this array
|
51
|
-
@notices = Array.new # information on successful transmissions are put in this array
|
52
41
|
# Variables used for monitoring state of transmission:
|
53
42
|
@session = nil # TCP connection
|
54
43
|
@association = nil # DICOM Association status
|
@@ -70,10 +59,10 @@ module DICOM
|
|
70
59
|
if info[:pdu] != PDU_RELEASE_REQUEST
|
71
60
|
# For some reason we didnt get our expected release request. Determine why:
|
72
61
|
if info[:valid]
|
73
|
-
|
62
|
+
logger.error("Unexpected message type received (PDU: #{info[:pdu]}). Expected a release request. Closing the connection.")
|
74
63
|
handle_abort(false)
|
75
64
|
else
|
76
|
-
|
65
|
+
logger.error("Timed out while waiting for a release request. Closing the connection.")
|
77
66
|
end
|
78
67
|
stop_session
|
79
68
|
else
|
@@ -368,7 +357,7 @@ module DICOM
|
|
368
357
|
info = interpret_abort(message)
|
369
358
|
else
|
370
359
|
info = {:valid => false}
|
371
|
-
|
360
|
+
logger.error("An unknown PDU type was received in the incoming transmission. Can not decode this message. (PDU: #{pdu})")
|
372
361
|
end
|
373
362
|
return info
|
374
363
|
end
|
@@ -380,7 +369,7 @@ module DICOM
|
|
380
369
|
# * <tt>default_message</tt> -- A boolean which unless set as nil/false will make the method print the default status message.
|
381
370
|
#
|
382
371
|
def handle_abort(default_message=true)
|
383
|
-
|
372
|
+
logger.warn("An unregonizable (non-DICOM) message was received.") if default_message
|
384
373
|
build_association_abort
|
385
374
|
transmit
|
386
375
|
end
|
@@ -453,7 +442,7 @@ module DICOM
|
|
453
442
|
# Handles the rejection message (The response used to an association request when its formalities are not correct).
|
454
443
|
#
|
455
444
|
def handle_rejection
|
456
|
-
|
445
|
+
logger.warn("An incoming association request was rejected. Error code: #{association_error}")
|
457
446
|
# Insert the error code in the info hash:
|
458
447
|
info[:reason] = association_error
|
459
448
|
# Send an association rejection:
|
@@ -465,7 +454,7 @@ module DICOM
|
|
465
454
|
#
|
466
455
|
def handle_release
|
467
456
|
stop_receiving
|
468
|
-
|
457
|
+
logger.info("Received a release request. Releasing association.")
|
469
458
|
build_release_response
|
470
459
|
transmit
|
471
460
|
stop_session
|
@@ -557,7 +546,7 @@ module DICOM
|
|
557
546
|
end
|
558
547
|
else
|
559
548
|
# Length of the message is less than what is specified in the message. Need to listen for more. This is hopefully handled properly now.
|
560
|
-
#
|
549
|
+
#logger.error("Error. The length of the received message (#{msg.rest_length}) is smaller than what it claims (#{specified_length}). Aborting.")
|
561
550
|
@first_part = msg.string
|
562
551
|
end
|
563
552
|
else
|
@@ -707,7 +696,7 @@ module DICOM
|
|
707
696
|
else
|
708
697
|
# Value (variable length)
|
709
698
|
value = msg.decode(item_length, "STR")
|
710
|
-
|
699
|
+
logger.warn("Unknown user info item type received. Please update source code or contact author. (item type: #{item_type})")
|
711
700
|
end
|
712
701
|
end
|
713
702
|
stop_receiving
|
@@ -733,7 +722,7 @@ module DICOM
|
|
733
722
|
info[:source] = msg.decode(1, "BY")
|
734
723
|
# Reason (1 byte)
|
735
724
|
info[:reason] = msg.decode(1, "BY")
|
736
|
-
|
725
|
+
logger.warn("ASSOCIATE Request was rejected by the host. Error codes: Result: #{info[:result]}, Source: #{info[:source]}, Reason: #{info[:reason]} (See DICOM PS3.8: Table 9-21 for details.)")
|
737
726
|
stop_receiving
|
738
727
|
info[:valid] = true
|
739
728
|
return info
|
@@ -877,7 +866,7 @@ module DICOM
|
|
877
866
|
# Unknown item type:
|
878
867
|
# Value (variable length)
|
879
868
|
value = msg.decode(item_length, "STR")
|
880
|
-
|
869
|
+
logger.warn("Unknown user info item type received. Please update source code or contact author. (item type: " + item_type + ")")
|
881
870
|
end
|
882
871
|
end
|
883
872
|
stop_receiving
|
@@ -923,7 +912,7 @@ module DICOM
|
|
923
912
|
# Length (2 bytes)
|
924
913
|
length = msg.decode(2, "US")
|
925
914
|
if length > msg.rest_length
|
926
|
-
|
915
|
+
logger.error("Specified length of command element value exceeds remaining length of the received message! Something is wrong.")
|
927
916
|
end
|
928
917
|
# Reserved (2 bytes)
|
929
918
|
msg.skip(2)
|
@@ -948,7 +937,7 @@ module DICOM
|
|
948
937
|
end
|
949
938
|
# Special case: Handle a possible C-ECHO-RQ:
|
950
939
|
if info[:results]["0000,0100"] == C_ECHO_RQ
|
951
|
-
|
940
|
+
logger.info("Received an Echo request. Returning an Echo response.")
|
952
941
|
handle_response
|
953
942
|
end
|
954
943
|
elsif info[:presentation_context_flag] == DATA_MORE_FRAGMENTS or info[:presentation_context_flag] == DATA_LAST_FRAGMENT
|
@@ -977,7 +966,7 @@ module DICOM
|
|
977
966
|
length = msg.decode(4, "UL")
|
978
967
|
end
|
979
968
|
if length > msg.rest_length
|
980
|
-
|
969
|
+
logger.error("The specified length of the data element value exceeds the remaining length of the received message!")
|
981
970
|
end
|
982
971
|
# Fetch the name (& type if not defined already) for this data element:
|
983
972
|
result = LIBRARY.get_name_vr(tag)
|
@@ -993,7 +982,7 @@ module DICOM
|
|
993
982
|
end
|
994
983
|
else
|
995
984
|
# Unknown.
|
996
|
-
|
985
|
+
logger.error("Unknown presentation context flag received in the query/command response. (#{info[:presentation_context_flag]})")
|
997
986
|
stop_receiving
|
998
987
|
end
|
999
988
|
# If only parts of the string was read, return the rest:
|
@@ -1108,30 +1097,6 @@ module DICOM
|
|
1108
1097
|
private
|
1109
1098
|
|
1110
1099
|
|
1111
|
-
# Adds a warning or error message to the instance array holding messages,
|
1112
|
-
# and prints the information to the screen if verbose is set.
|
1113
|
-
#
|
1114
|
-
# === Parameters
|
1115
|
-
#
|
1116
|
-
# * <tt>error</tt> -- A single error message or an array of error messages.
|
1117
|
-
#
|
1118
|
-
def add_error(error)
|
1119
|
-
puts error if @verbose
|
1120
|
-
@errors << error
|
1121
|
-
end
|
1122
|
-
|
1123
|
-
# Adds a notice (information regarding progress or successful communications) to the instance array,
|
1124
|
-
# and prints the information to the screen if verbose is set.
|
1125
|
-
#
|
1126
|
-
# === Parameters
|
1127
|
-
#
|
1128
|
-
# * <tt>notice</tt> -- A single status message or an array of status messages.
|
1129
|
-
#
|
1130
|
-
def add_notice(notice)
|
1131
|
-
puts notice if @verbose
|
1132
|
-
@notices << notice
|
1133
|
-
end
|
1134
|
-
|
1135
1100
|
# Builds the application context (which is part of the association request/response).
|
1136
1101
|
#
|
1137
1102
|
def append_application_context
|
@@ -1299,7 +1264,7 @@ module DICOM
|
|
1299
1264
|
when C_ECHO_RQ
|
1300
1265
|
return C_ECHO_RSP
|
1301
1266
|
else
|
1302
|
-
|
1267
|
+
logger.error("Unknown or unsupported request (#{request}) encountered.")
|
1303
1268
|
return C_CANCEL_RQ
|
1304
1269
|
end
|
1305
1270
|
end
|
@@ -1313,19 +1278,19 @@ module DICOM
|
|
1313
1278
|
def process_reason(reason)
|
1314
1279
|
case reason
|
1315
1280
|
when "00"
|
1316
|
-
|
1281
|
+
logger.error("Reason specified for abort: Reason not specified")
|
1317
1282
|
when "01"
|
1318
|
-
|
1283
|
+
logger.error("Reason specified for abort: Unrecognized PDU")
|
1319
1284
|
when "02"
|
1320
|
-
|
1285
|
+
logger.error("Reason specified for abort: Unexpected PDU")
|
1321
1286
|
when "04"
|
1322
|
-
|
1287
|
+
logger.error("Reason specified for abort: Unrecognized PDU parameter")
|
1323
1288
|
when "05"
|
1324
|
-
|
1289
|
+
logger.error("Reason specified for abort: Unexpected PDU parameter")
|
1325
1290
|
when "06"
|
1326
|
-
|
1291
|
+
logger.error("Reason specified for abort: Invalid PDU parameter value")
|
1327
1292
|
else
|
1328
|
-
|
1293
|
+
logger.error("Reason specified for abort: Unknown reason (Error code: #{reason})")
|
1329
1294
|
end
|
1330
1295
|
end
|
1331
1296
|
|
@@ -1345,15 +1310,15 @@ module DICOM
|
|
1345
1310
|
# Analyse the result and report what is wrong:
|
1346
1311
|
case result
|
1347
1312
|
when 1
|
1348
|
-
|
1313
|
+
logger.warn("DICOM Request was rejected by the host, reason: 'User-rejection'")
|
1349
1314
|
when 2
|
1350
|
-
|
1315
|
+
logger.warn("DICOM Request was rejected by the host, reason: 'No reason (provider rejection)'")
|
1351
1316
|
when 3
|
1352
|
-
|
1317
|
+
logger.warn("DICOM Request was rejected by the host, reason: 'Abstract syntax not supported'")
|
1353
1318
|
when 4
|
1354
|
-
|
1319
|
+
logger.warn("DICOM Request was rejected by the host, reason: 'Transfer syntaxes not supported'")
|
1355
1320
|
else
|
1356
|
-
|
1321
|
+
logger.warn("DICOM Request was rejected by the host, reason: 'UNKNOWN (#{result})' (Illegal reason provided)")
|
1357
1322
|
end
|
1358
1323
|
end
|
1359
1324
|
end
|
@@ -1366,11 +1331,11 @@ module DICOM
|
|
1366
1331
|
#
|
1367
1332
|
def process_source(source)
|
1368
1333
|
if source == "00"
|
1369
|
-
|
1334
|
+
logger.warn("Connection has been aborted by the service provider because of an error by the service user (client side).")
|
1370
1335
|
elsif source == "02"
|
1371
|
-
|
1336
|
+
logger.warn("Connection has been aborted by the service provider because of an error by the service provider (server side).")
|
1372
1337
|
else
|
1373
|
-
|
1338
|
+
logger.warn("Connection has been aborted by the service provider, with an unknown cause of the problems. (error code: #{source})")
|
1374
1339
|
end
|
1375
1340
|
end
|
1376
1341
|
|
@@ -1391,26 +1356,26 @@ module DICOM
|
|
1391
1356
|
case status
|
1392
1357
|
when 0 # "0000"
|
1393
1358
|
# Last fragment (Break the while loop that listens continuously for incoming packets):
|
1394
|
-
|
1359
|
+
logger.info("Receipt for successful execution of the desired operation has been received.")
|
1395
1360
|
stop_receiving
|
1396
1361
|
when 42752 # "a700"
|
1397
1362
|
# Failure: Out of resources. Related fields: 0000,0902
|
1398
|
-
|
1363
|
+
logger.error("Failure! SCP has given the following reason: 'Out of Resources'.")
|
1399
1364
|
when 43264 # "a900"
|
1400
1365
|
# Failure: Identifier Does Not Match SOP Class. Related fields: 0000,0901, 0000,0902
|
1401
|
-
|
1366
|
+
logger.error("Failure! SCP has given the following reason: 'Identifier Does Not Match SOP Class'.")
|
1402
1367
|
when 49152 # "c000"
|
1403
1368
|
# Failure: Unable to process. Related fields: 0000,0901, 0000,0902
|
1404
|
-
|
1369
|
+
logger.error("Failure! SCP has given the following reason: 'Unable to process'.")
|
1405
1370
|
when 49408 # "c100"
|
1406
1371
|
# Failure: More than one match found. Related fields: 0000,0901, 0000,0902
|
1407
|
-
|
1372
|
+
logger.error("Failure! SCP has given the following reason: 'More than one match found'.")
|
1408
1373
|
when 49664 # "c200"
|
1409
1374
|
# Failure: Unable to support requested template. Related fields: 0000,0901, 0000,0902
|
1410
|
-
|
1375
|
+
logger.error("Failure! SCP has given the following reason: 'Unable to support requested template'.")
|
1411
1376
|
when 65024 # "fe00"
|
1412
1377
|
# Cancel: Matching terminated due to Cancel request.
|
1413
|
-
|
1378
|
+
logger.info("Cancel! SCP has given the following reason: 'Matching terminated due to Cancel request'.")
|
1414
1379
|
when 65280 # "ff00"
|
1415
1380
|
# Sub-operations are continuing.
|
1416
1381
|
# (No particular action taken, the program will listen for and receive the coming fragments)
|
@@ -1418,7 +1383,7 @@ module DICOM
|
|
1418
1383
|
# More command/data fragments to follow.
|
1419
1384
|
# (No particular action taken, the program will listen for and receive the coming fragments)
|
1420
1385
|
else
|
1421
|
-
|
1386
|
+
logger.error("Something was NOT successful regarding the desired operation. SCP responded with error code: #{status} (tag: 0000,0900). See DICOM PS3.7, Annex C for details.")
|
1422
1387
|
end
|
1423
1388
|
end
|
1424
1389
|
|
@@ -1465,7 +1430,7 @@ module DICOM
|
|
1465
1430
|
while @receive
|
1466
1431
|
if (Time.now.to_f - t1) > @timeout
|
1467
1432
|
Thread.kill(thr)
|
1468
|
-
|
1433
|
+
logger.error("No answer was received within the specified timeout period. Aborting.")
|
1469
1434
|
stop_receiving
|
1470
1435
|
end
|
1471
1436
|
end
|
@@ -1497,7 +1462,7 @@ module DICOM
|
|
1497
1462
|
# Query the library with our particular transfer syntax string:
|
1498
1463
|
valid_syntax, @explicit, @data_endian = LIBRARY.process_transfer_syntax(syntax)
|
1499
1464
|
unless valid_syntax
|
1500
|
-
|
1465
|
+
logger.warn("Invalid (unknown) transfer syntax encountered! Will try to continue, but errors may occur.")
|
1501
1466
|
end
|
1502
1467
|
end
|
1503
1468
|
|
@@ -1564,4 +1529,4 @@ module DICOM
|
|
1564
1529
|
end
|
1565
1530
|
|
1566
1531
|
end
|
1567
|
-
end
|
1532
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module DICOM
|
2
|
+
|
3
|
+
# This module handles logging functionality.
|
4
|
+
#
|
5
|
+
# Logging functionality uses the Standard library's Logger class.
|
6
|
+
# To properly handle progname, which inside the DICOM module is simply
|
7
|
+
# "DICOM", in all cases, we use an implementation with a proxy class.
|
8
|
+
#
|
9
|
+
# === Examples
|
10
|
+
#
|
11
|
+
# require 'dicom'
|
12
|
+
# include DICOM
|
13
|
+
#
|
14
|
+
# # Logging to STDOUT with DEBUG level:
|
15
|
+
# DICOM.logger = Logger.new(STDOUT)
|
16
|
+
# DICOM.logger.level = Logger::DEBUG
|
17
|
+
#
|
18
|
+
# # Logging to a file:
|
19
|
+
# DICOM.logger = Logger.new('my_logfile.log')
|
20
|
+
#
|
21
|
+
# # Combine an external logger with DICOM:
|
22
|
+
# logger = Logger.new(STDOUT)
|
23
|
+
# logger.progname = "MY_APP"
|
24
|
+
# DICOM.logger = logger
|
25
|
+
# # Now you can call the logger in the following ways:
|
26
|
+
# DICOM.logger.info "Message" # => "DICOM: Message"
|
27
|
+
# DICOM.logger.info("MY_MODULE) {"Message"} # => "MY_MODULE: Message"
|
28
|
+
# logger.info "Message" # => "MY_APP: Message"
|
29
|
+
#
|
30
|
+
# For more information, please read the Standard library Logger documentation.
|
31
|
+
#
|
32
|
+
module Logging
|
33
|
+
|
34
|
+
require 'logger'
|
35
|
+
|
36
|
+
# Inclusion hook to make the ClassMethods available to whatever
|
37
|
+
# includes the Logging module, i.e. the DICOM module.
|
38
|
+
#
|
39
|
+
def self.included(base)
|
40
|
+
base.extend(ClassMethods)
|
41
|
+
end
|
42
|
+
|
43
|
+
module ClassMethods
|
44
|
+
|
45
|
+
# We use our own ProxyLogger to achieve the features wanted for DICOM logging,
|
46
|
+
# e.g. using DICOM as progname for messages logged within the DICOM module
|
47
|
+
# (for both the Standard logger as well as the Rails logger), while still allowing
|
48
|
+
# a custom progname to be used when the logger is called outside the DICOM module.
|
49
|
+
#
|
50
|
+
class ProxyLogger
|
51
|
+
|
52
|
+
# Creating the ProxyLogger instance.
|
53
|
+
#
|
54
|
+
# === Parameters
|
55
|
+
#
|
56
|
+
# * <tt>target</tt> -- A Logger instance (e.g. Standard Logger or ActiveSupport::BufferedLogger).
|
57
|
+
#
|
58
|
+
def initialize(target)
|
59
|
+
@target = target
|
60
|
+
end
|
61
|
+
|
62
|
+
# Catches missing methods.
|
63
|
+
# In our case, the methods of interest are the typical logger methods,
|
64
|
+
# i.e. log, info, fatal, error, debug, where the arguments/block are
|
65
|
+
# redirected to the logger in a specific way so that our stated logger
|
66
|
+
# features are achieved (this behaviour depends on the logger
|
67
|
+
# (Rails vs Standard) and in the case of Standard logger,
|
68
|
+
# whether or not a block is given).
|
69
|
+
#
|
70
|
+
# === Examples
|
71
|
+
#
|
72
|
+
# # Inside the DICOM module or an external class with 'include DICOM::Logging':
|
73
|
+
# logger.info "message"
|
74
|
+
#
|
75
|
+
# # Calling from outside the DICOM module:
|
76
|
+
# DICOM.logger.info "message"
|
77
|
+
#
|
78
|
+
def method_missing(method_name, *args, &block)
|
79
|
+
if method_name.to_s =~ /(log|debug|info|warn|error|fatal)/
|
80
|
+
# Rails uses it's own buffered logger which does not
|
81
|
+
# work with progname + block as the standard logger does:
|
82
|
+
if defined?(Rails)
|
83
|
+
@target.send(method_name, "DICOM: #{args.first}")
|
84
|
+
elsif block_given?
|
85
|
+
@target.send(method_name, *args) { yield }
|
86
|
+
else
|
87
|
+
@target.send(method_name, "DICOM") { args.first }
|
88
|
+
end
|
89
|
+
else
|
90
|
+
@target.send(method_name, *args, &block)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
# The logger class variable (must be initialized
|
97
|
+
# before it is referenced by the object setter).
|
98
|
+
#
|
99
|
+
@@logger = nil
|
100
|
+
|
101
|
+
# The logger object setter.
|
102
|
+
# This method is used to replace the default logger instance with
|
103
|
+
# a custom logger of your own.
|
104
|
+
#
|
105
|
+
# === Parameters
|
106
|
+
#
|
107
|
+
# * <tt>l</tt> -- A Logger instance (e.g. a custom standard Logger).
|
108
|
+
#
|
109
|
+
# === Examples
|
110
|
+
#
|
111
|
+
# # Create a logger which ages logfile once it reaches a certain size,
|
112
|
+
# # leaves 10 "old log files" with each file being about 1,024,000 bytes:
|
113
|
+
# DICOM.logger = Logger.new('foo.log', 10, 1024000)
|
114
|
+
#
|
115
|
+
def logger=(l)
|
116
|
+
@@logger = ProxyLogger.new(l)
|
117
|
+
end
|
118
|
+
|
119
|
+
# The logger object getter.
|
120
|
+
# Returns the logger class variable, if defined.
|
121
|
+
# If not defined, sets up the Rails logger (if in a Rails environment),
|
122
|
+
# or a Standard logger if not.
|
123
|
+
#
|
124
|
+
# === Examples
|
125
|
+
#
|
126
|
+
# # Inside the DICOM module (or a class with 'include DICOM::Logging'):
|
127
|
+
# logger # => Logger instance
|
128
|
+
#
|
129
|
+
# # Accessing from outside the DICOM module:
|
130
|
+
# DICOM.logger # => Logger instance
|
131
|
+
#
|
132
|
+
def logger
|
133
|
+
@@logger ||= lambda {
|
134
|
+
if defined?(Rails)
|
135
|
+
ProxyLogger.new(Rails.logger)
|
136
|
+
else
|
137
|
+
l = Logger.new(STDOUT)
|
138
|
+
l.level = Logger::INFO
|
139
|
+
ProxyLogger.new(l)
|
140
|
+
end
|
141
|
+
}.call
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
# A logger object getter.
|
147
|
+
# Forwards the call to the logger class method of the Logging module.
|
148
|
+
#
|
149
|
+
def logger
|
150
|
+
self.class.logger
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
# Include the Logging module so we can use DICOM.logger.
|
156
|
+
include Logging
|
157
|
+
|
158
|
+
end
|