code: def _replace_url(self, match: re.Match) -> bytes:
      remote_port = int(match.group(1))
      if remote_port not in self.ports:
          return match.group(0)
      local_port = self.ports[remote_port]
      omit_port = (not self.secure and local_port == 80) or (
          self.secure and local_port == 443
      )
  
      app_spec = self.app_specs.get(remote_port)
      url = urllib.parse.urlparse(match.group(0))
      qs = {
          k: v[0] for k, v in urllib.parse.parse_qs(url.query).items()
      }
      if app_spec and app_spec.url_query_params is not None:
          qs.update(
              {
                  k.encode(): v.encode()
                  for k, v in app_spec.url_query_params.items()
              }
          )
  
      url = url._replace(
          scheme=("https" if self.secure else "http").encode(),
          netloc=(
              self.hostname
              if omit_port
              else f"{self.hostname}:{local_port}"
          ).encode(),
          query=urllib.parse.urlencode(qs).encode(),
      )
      return url.geturl()
  
file_path: dstack/src/dstack/_internal/core/services/logs.py
imports: import re
  import urllib.parse
  from typing import Dict, List, Optional
  from dstack._internal.core.models.runs import AppSpec
label_desc: Use image node_id 2 for calling the URLReplacer obj's underlying member method code with example usage: obj._replace_url(match) and returns: url, match