|
14 | 14 | # ============================================================================== |
15 | 15 | """TensorBoard WSGI Application Logic. |
16 | 16 |
|
17 | | -TensorBoardApplication constructs TensorBoard as a WSGI application. |
18 | | -It handles serving static assets, and implements TensorBoard data APIs. |
| 17 | +Provides TensorBoardWSGIApp for building a TensorBoard WSGI app. |
19 | 18 | """ |
20 | 19 |
|
21 | 20 | from __future__ import absolute_import |
@@ -107,64 +106,98 @@ def standard_tensorboard_wsgi(flags, plugin_loaders, assets_zip_provider): |
107 | 106 | :type plugin_loaders: list[base_plugin.TBLoader] |
108 | 107 | :rtype: TensorBoardWSGI |
109 | 108 | """ |
110 | | - event_file_active_filter = _get_event_file_active_filter(flags) |
111 | | - multiplexer = event_multiplexer.EventMultiplexer( |
112 | | - size_guidance=DEFAULT_SIZE_GUIDANCE, |
113 | | - tensor_size_guidance=tensor_size_guidance_from_flags(flags), |
114 | | - purge_orphaned_data=flags.purge_orphaned_data, |
115 | | - max_reload_threads=flags.max_reload_threads, |
116 | | - event_file_active_filter=event_file_active_filter) |
117 | | - if flags.generic_data == 'false': |
118 | | - data_provider = None |
119 | | - else: |
120 | | - data_provider = event_data_provider.MultiplexerDataProvider(multiplexer) |
121 | | - loading_multiplexer = multiplexer |
| 109 | + data_provider = None |
| 110 | + multiplexer = None |
122 | 111 | reload_interval = flags.reload_interval |
123 | | - db_uri = flags.db |
124 | | - db_connection_provider = None |
125 | | - # For DB import mode, create a DB file if we weren't given one. |
126 | | - if flags.db_import and not flags.db: |
127 | | - tmpdir = tempfile.mkdtemp(prefix='tbimport') |
128 | | - atexit.register(shutil.rmtree, tmpdir) |
129 | | - db_uri = 'sqlite:%s/tmp.sqlite' % tmpdir |
130 | 112 | if flags.db_import: |
131 | 113 | # DB import mode. |
132 | | - logger.info('Importing logdir into DB at %s', db_uri) |
| 114 | + db_uri = flags.db |
| 115 | + # Create a temporary DB file if we weren't given one. |
| 116 | + if not db_uri: |
| 117 | + tmpdir = tempfile.mkdtemp(prefix='tbimport') |
| 118 | + atexit.register(shutil.rmtree, tmpdir) |
| 119 | + db_uri = 'sqlite:%s/tmp.sqlite' % tmpdir |
133 | 120 | db_connection_provider = create_sqlite_connection_provider(db_uri) |
134 | | - loading_multiplexer = db_import_multiplexer.DbImportMultiplexer( |
| 121 | + logger.info('Importing logdir into DB at %s', db_uri) |
| 122 | + multiplexer = db_import_multiplexer.DbImportMultiplexer( |
| 123 | + db_uri=db_uri, |
135 | 124 | db_connection_provider=db_connection_provider, |
136 | 125 | purge_orphaned_data=flags.purge_orphaned_data, |
137 | 126 | max_reload_threads=flags.max_reload_threads) |
138 | 127 | elif flags.db: |
139 | 128 | # DB read-only mode, never load event logs. |
140 | 129 | reload_interval = -1 |
141 | | - db_connection_provider = create_sqlite_connection_provider(db_uri) |
| 130 | + db_connection_provider = create_sqlite_connection_provider(flags.db) |
| 131 | + multiplexer = _DbModeMultiplexer(flags.db, db_connection_provider) |
| 132 | + else: |
| 133 | + # Regular logdir loading mode. |
| 134 | + multiplexer = event_multiplexer.EventMultiplexer( |
| 135 | + size_guidance=DEFAULT_SIZE_GUIDANCE, |
| 136 | + tensor_size_guidance=tensor_size_guidance_from_flags(flags), |
| 137 | + purge_orphaned_data=flags.purge_orphaned_data, |
| 138 | + max_reload_threads=flags.max_reload_threads, |
| 139 | + event_file_active_filter=_get_event_file_active_filter(flags)) |
| 140 | + if flags.generic_data != 'false': |
| 141 | + data_provider = event_data_provider.MultiplexerDataProvider(multiplexer) |
| 142 | + |
| 143 | + if reload_interval >= 0: |
| 144 | + # We either reload the multiplexer once when TensorBoard starts up, or we |
| 145 | + # continuously reload the multiplexer. |
| 146 | + path_to_run = parse_event_files_spec(flags.logdir) |
| 147 | + start_reloading_multiplexer( |
| 148 | + multiplexer, path_to_run, reload_interval, flags.reload_task) |
| 149 | + return TensorBoardWSGIApp( |
| 150 | + flags, plugin_loaders, data_provider, assets_zip_provider, multiplexer) |
| 151 | + |
| 152 | + |
| 153 | +def TensorBoardWSGIApp( |
| 154 | + flags, |
| 155 | + plugins, |
| 156 | + data_provider=None, |
| 157 | + assets_zip_provider=None, |
| 158 | + deprecated_multiplexer=None): |
| 159 | + """Constructs a TensorBoard WSGI app from plugins and data providers. |
| 160 | +
|
| 161 | + Args: |
| 162 | + flags: An argparse.Namespace containing TensorBoard CLI flags. |
| 163 | + plugins: A list of TBLoader subclasses for the plugins to load. |
| 164 | + assets_zip_provider: See TBContext documentation for more information. |
| 165 | + data_provider: Instance of `tensorboard.data.provider.DataProvider`. May |
| 166 | + be `None` if `flags.generic_data` is set to `"false"` in which case |
| 167 | + `deprecated_multiplexer` must be passed instead. |
| 168 | + deprecated_multiplexer: Optional `plugin_event_multiplexer.EventMultiplexer` |
| 169 | + to use for any plugins not yet enabled for the DataProvider API. |
| 170 | + Required if the data_provider argument is not passed. |
| 171 | +
|
| 172 | + Returns: |
| 173 | + A WSGI application that implements the TensorBoard backend. |
| 174 | + """ |
| 175 | + db_uri = None |
| 176 | + db_connection_provider = None |
| 177 | + if isinstance( |
| 178 | + deprecated_multiplexer, |
| 179 | + (db_import_multiplexer.DbImportMultiplexer, _DbModeMultiplexer)): |
| 180 | + db_uri = deprecated_multiplexer.db_uri |
| 181 | + db_connection_provider = deprecated_multiplexer.db_connection_provider |
142 | 182 | plugin_name_to_instance = {} |
143 | 183 | context = base_plugin.TBContext( |
144 | 184 | data_provider=data_provider, |
145 | 185 | db_connection_provider=db_connection_provider, |
146 | 186 | db_uri=db_uri, |
147 | 187 | flags=flags, |
148 | 188 | logdir=flags.logdir, |
149 | | - multiplexer=multiplexer, |
| 189 | + multiplexer=deprecated_multiplexer, |
150 | 190 | assets_zip_provider=assets_zip_provider, |
151 | 191 | plugin_name_to_instance=plugin_name_to_instance, |
152 | 192 | window_title=flags.window_title) |
153 | | - plugins = [] |
154 | | - for loader in plugin_loaders: |
| 193 | + tbplugins = [] |
| 194 | + for loader in plugins: |
155 | 195 | plugin = loader.load(context) |
156 | 196 | if plugin is None: |
157 | 197 | continue |
158 | | - plugins.append(plugin) |
| 198 | + tbplugins.append(plugin) |
159 | 199 | plugin_name_to_instance[plugin.plugin_name] = plugin |
160 | | - |
161 | | - if reload_interval >= 0: |
162 | | - # We either reload the multiplexer once when TensorBoard starts up, or we |
163 | | - # continuously reload the multiplexer. |
164 | | - path_to_run = parse_event_files_spec(flags.logdir) |
165 | | - start_reloading_multiplexer( |
166 | | - loading_multiplexer, path_to_run, reload_interval, flags.reload_task) |
167 | | - return TensorBoardWSGI(plugins, flags.path_prefix) |
| 200 | + return TensorBoardWSGI(tbplugins, flags.path_prefix) |
168 | 201 |
|
169 | 202 |
|
170 | 203 | class TensorBoardWSGI(object): |
@@ -531,3 +564,40 @@ def _get_event_file_active_filter(flags): |
531 | 564 | if inactive_secs < 0: |
532 | 565 | return lambda timestamp: True |
533 | 566 | return lambda timestamp: timestamp + inactive_secs >= time.time() |
| 567 | + |
| 568 | + |
| 569 | +class _DbModeMultiplexer(event_multiplexer.EventMultiplexer): |
| 570 | + """Shim EventMultiplexer to use when in read-only DB mode. |
| 571 | +
|
| 572 | + In read-only DB mode, the EventMultiplexer is nonfunctional - there is no |
| 573 | + logdir to reload, and the data is all exposed via SQL. This class represents |
| 574 | + the do-nothing EventMultiplexer for that purpose, which serves only as a |
| 575 | + conduit for DB-related parameters. |
| 576 | +
|
| 577 | + The load APIs raise exceptions if called, and the read APIs always |
| 578 | + return empty results. |
| 579 | + """ |
| 580 | + def __init__(self, db_uri, db_connection_provider): |
| 581 | + """Constructor for `_DbModeMultiplexer`. |
| 582 | +
|
| 583 | + Args: |
| 584 | + db_uri: A URI to the database file in use. |
| 585 | + db_connection_provider: Provider function for creating a DB connection. |
| 586 | + """ |
| 587 | + logger.info('_DbModeMultiplexer initializing for %s', db_uri) |
| 588 | + super(_DbModeMultiplexer, self).__init__() |
| 589 | + self.db_uri = db_uri |
| 590 | + self.db_connection_provider = db_connection_provider |
| 591 | + logger.info('_DbModeMultiplexer done initializing') |
| 592 | + |
| 593 | + def AddRun(self, path, name=None): |
| 594 | + """Unsupported.""" |
| 595 | + raise NotImplementedError() |
| 596 | + |
| 597 | + def AddRunsFromDirectory(self, path, name=None): |
| 598 | + """Unsupported.""" |
| 599 | + raise NotImplementedError() |
| 600 | + |
| 601 | + def Reload(self): |
| 602 | + """Unsupported.""" |
| 603 | + raise NotImplementedError() |
0 commit comments